diff --git a/fceu-server/.gitignore b/fceu-server/.gitignore new file mode 100644 index 00000000..674deb69 --- /dev/null +++ b/fceu-server/.gitignore @@ -0,0 +1,17 @@ +# A simulation of Subversion default ignores, generated by reposurgeon. +*.o +*.lo +*.la +*.al +*.libs +*.so +*.so.[0-9]* +*.a +*.pyc +*.pyo +*.rej +*~ +*.#* +.*.swp +.DS_store +# Simulated Subversion default ignores end here diff --git a/fceu-server/AUTHORS b/fceu-server/AUTHORS new file mode 100644 index 00000000..0888cb48 --- /dev/null +++ b/fceu-server/AUTHORS @@ -0,0 +1,2 @@ +Major developer: Xodnizel +Interface changes and all releases past 0.0.3: Lukas Sabota diff --git a/fceu-server/COPYING b/fceu-server/COPYING new file mode 100644 index 00000000..45645b4b --- /dev/null +++ b/fceu-server/COPYING @@ -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. + + + Copyright (C) + + 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) year 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. + + , 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. diff --git a/fceu-server/ChangeLog b/fceu-server/ChangeLog new file mode 100644 index 00000000..89dde3c4 --- /dev/null +++ b/fceu-server/ChangeLog @@ -0,0 +1,30 @@ +0.0.5: + Interface received massive overhaul. Now takes command line + options. This will allow the server to communicate with + other front-ends. Integration can now occur in gfceu. + +0.0.4: + Renamed from "server" to "fceu-server". + Renamed standard.conf -> fceu-standard.conf + If no configuration file is specified, look in /etc and ./ + Added a --help option. + Added GPL headers + +0.0.3: + Error messages during server startup are more verbose(slightly). + + Fixed initialization of the sockaddr_in structure, sin_family + member. It's now initialized to AF_INET before calling bind(). + While not initializing that member seemed to work ok on + Linux 2.4, it won't work on Linux 2.2 and under Cygwin, + and possibly other environments. + +0.0.2: + Switched to using fcntl() to set the socket to nonblocking, + so I don't need to use MSG_NOWAIT in send() anymore, which is + undefined under Cygwin. + + Added a "clean" Makefile target. + +0.0.1: + First Release diff --git a/fceu-server/Makefile b/fceu-server/Makefile new file mode 100644 index 00000000..f30c82e3 --- /dev/null +++ b/fceu-server/Makefile @@ -0,0 +1,20 @@ +PREFIX = /usr +OUTFILE = fceu-server + +CC = g++ +OBJS = server.o md5.o throttle.o + + +all: ${OBJS} + ${CC} -o ${OUTFILE} ${OBJS} + +clean: + rm -f ${OUTFILE} ${OBJS} + +install: + install -m 755 -D fceu-server ${PREFIX}/bin/fceu-server + install -m 644 -D fceu-server.conf /etc/fceu-server.conf + +server.o: server.cpp +md5.o: md5.cpp +throttle.o: throttle.cpp diff --git a/fceu-server/README b/fceu-server/README new file mode 100644 index 00000000..1a4628a2 --- /dev/null +++ b/fceu-server/README @@ -0,0 +1,51 @@ +FCE Ultra Network Play Server v0.0.5 +------------------------------------ + +To compile, type this in the shell: +$ make +To install, type this in this shell: +$ sudo make install +To run, type this in shell: +$ ./fceu-server + +To compile under MS Windows, you should use Cygwin. I'm not +going to change this server to use Win-old-dirty-smelly-sock natively. + +If it doesn't compile, sell your to the +. + +Most beings can run it like "./fceu-server >logfile &". +Windows users can run it some other way. A batch file with absolute paths, perhaps? + snuggums.bat: + C:\somethingdirectory\server.exe c:\somethingdirectory\standard.conf + +With the default settings, each client should use about 65-70Kbps, excluding any +data transferred during chat, state loads, etc(which should be negligible, but limits +will be placed on these types of transfers in the future). + +Clients connecting with high-latency or slow links may use more bandwidth, or they +may use less bandwidth. I'm really not quite sure. If it concerns you, test it. + +Any client connecting over VERY high latency links, such as bidirectional satellite connections, +may find that attempting network play will lock up his/her connection for +several minutes. Right, Disch. ;) + +The server probably won't scale well to a huge number of clients connected at the same time. + +Bumping up the server's priority and running it on a low-latency kernel(preferably with +1 ms or smaller timeslices) should help make network play more usable if you're running the +network play server on an otherwise non-idle physical server. + + + +TODO: + +Implement a more flexible timing system, so that PAL games will be playable. + +Change the protocol to allow the client to specify the size of input update information, +so devices like the powerpad or zapper can work over network play. + +Send emulation info, such as NTSC/PAL, input devices, and Game Genie emulation at connect +time, to make it easier on end users. + +On Mac OSX, server is reporting back to clients "Invalid number of players specified (0)". Running in a linux VM in bridged mode resolved this issue if you need to host the server on OSX. diff --git a/fceu-server/dist/fceu-server-0.0.4.tar.gz b/fceu-server/dist/fceu-server-0.0.4.tar.gz new file mode 100644 index 00000000..a7850742 Binary files /dev/null and b/fceu-server/dist/fceu-server-0.0.4.tar.gz differ diff --git a/fceu-server/dist/fceu-server-0.0.5.tar.gz b/fceu-server/dist/fceu-server-0.0.5.tar.gz new file mode 100644 index 00000000..95269b77 Binary files /dev/null and b/fceu-server/dist/fceu-server-0.0.5.tar.gz differ diff --git a/fceu-server/dist/fceunetserver-0.0.3.tar.bz2 b/fceu-server/dist/fceunetserver-0.0.3.tar.bz2 new file mode 100644 index 00000000..8d108224 Binary files /dev/null and b/fceu-server/dist/fceunetserver-0.0.3.tar.bz2 differ diff --git a/fceu-server/fceu-server.conf b/fceu-server/fceu-server.conf new file mode 100644 index 00000000..9c71a224 --- /dev/null +++ b/fceu-server/fceu-server.conf @@ -0,0 +1,5 @@ +maxclients 100 ; Maximum number of clients +connecttimeout 5 ; Connection(login) timeout +framedivisor 1 ; Frame divisor(eg: 60 / framedivisor updates per second) +port 4046 ; Port to listen on +;password sexybeef diff --git a/fceu-server/md5.cpp b/fceu-server/md5.cpp new file mode 100644 index 00000000..24dfd59f --- /dev/null +++ b/fceu-server/md5.cpp @@ -0,0 +1,266 @@ +/* FCE Ultra Network Play Server + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * */ + +/* + * RFC 1321 compliant MD5 implementation, + * by Christophe Devine ; + * this program is licensed under the GPL. + */ + +/* Modified October 3, 2003, to remove testing code, and add + include of "types.h". + + Added simple MD5 to ASCII string conversion function. + -Xodnizel +*/ + + + + +#include +#include "types.h" +#include "md5.h" + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ( (uint32) (b)[(i) + 3] << 24 ) \ + | ( (uint32) (b)[(i) + 2] << 16 ) \ + | ( (uint32) (b)[(i) + 1] << 8 ) \ + | ( (uint32) (b)[(i) ] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8) ( (n) ); \ + (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \ + (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \ + (b)[(i) + 3] = (uint8) ( (n) >> 24 ); \ +} + +void md5_starts( struct md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +void md5_process( struct md5_context *ctx, uint8 data[64] ) +{ + uint32 A, B, C, D, X[16]; + + GET_UINT32( X[0], data, 0 ); + GET_UINT32( X[1], data, 4 ); + GET_UINT32( X[2], data, 8 ); + GET_UINT32( X[3], data, 12 ); + GET_UINT32( X[4], data, 16 ); + GET_UINT32( X[5], data, 20 ); + GET_UINT32( X[6], data, 24 ); + GET_UINT32( X[7], data, 28 ); + GET_UINT32( X[8], data, 32 ); + GET_UINT32( X[9], data, 36 ); + GET_UINT32( X[10], data, 40 ); + GET_UINT32( X[11], data, 44 ); + GET_UINT32( X[12], data, 48 ); + GET_UINT32( X[13], data, 52 ); + GET_UINT32( X[14], data, 56 ); + GET_UINT32( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +void md5_update( struct md5_context *ctx, uint8 *input, uint32 length ) +{ + uint32 left, fill; + + if( ! length ) return; + + left = ( ctx->total[0] >> 3 ) & 0x3F; + fill = 64 - left; + + ctx->total[0] += length << 3; + ctx->total[1] += length >> 29; + + ctx->total[0] &= 0xFFFFFFFF; + ctx->total[1] += ctx->total[0] < ( length << 3 ); + + if( left && length >= fill ) + { + memcpy( (void *) (ctx->buffer + left), (void *) input, fill ); + md5_process( ctx, ctx->buffer ); + length -= fill; + input += fill; + left = 0; + } + + while( length >= 64 ) + { + md5_process( ctx, input ); + length -= 64; + input += 64; + } + + if( length ) + { + memcpy( (void *) (ctx->buffer + left), (void *) input, length ); + } +} + +static uint8 md5_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void md5_finish( struct md5_context *ctx, uint8 digest[16] ) +{ + uint32 last, padn; + uint8 msglen[8]; + + PUT_UINT32( ctx->total[0], msglen, 0 ); + PUT_UINT32( ctx->total[1], msglen, 4 ); + + last = ( ctx->total[0] >> 3 ) & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md5_update( ctx, md5_padding, padn ); + md5_update( ctx, msglen, 8 ); + + PUT_UINT32( ctx->state[0], digest, 0 ); + PUT_UINT32( ctx->state[1], digest, 4 ); + PUT_UINT32( ctx->state[2], digest, 8 ); + PUT_UINT32( ctx->state[3], digest, 12 ); +} + + +/* Uses a static buffer, so beware of how it's used. */ +char *md5_asciistr(uint8 digest[16]) +{ + static char str[33]; + static char trans[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + int x; + + for(x=0;x<16;x++) + { + str[x*2]=trans[digest[x]&0x0F]; + str[x*2+1]=trans[digest[x]>>4]; + } + return(str); +} diff --git a/fceu-server/md5.h b/fceu-server/md5.h new file mode 100644 index 00000000..6c5d4e87 --- /dev/null +++ b/fceu-server/md5.h @@ -0,0 +1,37 @@ +/* FCE Ultra Network Play Server + * + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef _MD5_H +#define _MD5_H + +struct md5_context +{ + uint32 total[2]; + uint32 state[4]; + uint8 buffer[64]; +}; + +void md5_starts( struct md5_context *ctx ); +void md5_update( struct md5_context *ctx, uint8 *input, uint32 length ); +void md5_finish( struct md5_context *ctx, uint8 digest[16] ); + +/* Uses a static buffer, so beware of how it's used. */ +char *md5_asciistr(uint8 digest[16]); + +#endif /* md5.h */ diff --git a/fceu-server/server.cpp b/fceu-server/server.cpp new file mode 100644 index 00000000..1cdfa5de --- /dev/null +++ b/fceu-server/server.cpp @@ -0,0 +1,914 @@ +/* FCE Ultra Network Play Server + * + * Copyright notice for this file: + * Copyright (C) 2004 Xodnizel + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "types.h" +#include "md5.h" +#include "throttle.h" + +#define VERSION "0.0.5" +#define DEFAULT_PORT 4046 +#define DEFAULT_MAX 100 +#define DEFAULT_TIMEOUT 5 +#define DEFAULT_FRAMEDIVISOR 1 +#define DEFAULT_CONFIG "/etc/fceu-server.conf" + +// MSG_NOSIGNAL and SOL_TCP have been depreciated on osx +#ifdef __APPLE__ +#define MSG_NOSIGNAL SO_NOSIGPIPE +#define SOL_TCP IPPROTO_TCP +#endif + +typedef struct { + uint32 id; /* mainly for faster referencing when pointed to from the Games + entries. + */ + char *nickname; + int TCPSocket; + void *game; /* Pointer to the game this player is in. */ + int localplayers; /* The number of local players, 1-4 */ + + time_t timeconnect; /* Time the client made the connection. */ + + /* Variables to handle non-blocking TCP reads. */ + uint8 *nbtcp; + uint32 nbtcphas, nbtcplen; + uint32 nbtcptype; +} ClientEntry; + +typedef struct +{ + uint8 id[16]; /* Unique 128-bit identifier for this game session. */ + uint8 joybuf[5]; /* 4 player data + 1 command byte */ + int MaxPlayers; /* Maximum players for this game */ + ClientEntry *Players[4]; /* Pointers to player data. */ + int IsUnique[4]; /* Set to 1 if player is unique client, 0 + if it's a duplicated entry to handle multiple players + per client. + */ + uint8 ExtraInfo[64]; /* Expansion information to be used in future versions + of FCE Ultra. + */ +} GameEntry; + +typedef struct +{ + unsigned int MaxClients; /* The maximum number of clients to allow. */ + /* You should expect each client to use + 65-70Kbps(not including save state loads) while + connected(and logged in), when using the default + FrameDivisor value of 1. + */ + unsigned int ConnectTimeout; /* How long to wait(in seconds) for the client to provide + login data before disconnecting the client. + */ + unsigned int FrameDivisor; /* The number of updates per second are divided + by this number. 1 = 60 updates/sec(approx), + 2 = 30 updates/sec, etc. */ + unsigned int Port; /* The port to listen on. */ + uint8 *Password; /* The server password. */ +} CONFIG; + +CONFIG ServerConfig; + +int LoadConfigFile(char *fn) +{ + FILE *fp; + ServerConfig.Port = ServerConfig.MaxClients = ServerConfig.ConnectTimeout = ServerConfig.FrameDivisor = ~0; + if(fp=fopen(fn,"rb")) + { + char buf[256]; + while(fgets(buf, 256, fp) > 0) + { + if(!strncasecmp(buf,"maxclients",strlen("maxclients"))) + sscanf(buf,"%*s %d",&ServerConfig.MaxClients); + else if(!strncasecmp(buf,"connecttimeout",strlen("connecttimeout"))) + sscanf(buf,"%*s %d",&ServerConfig.ConnectTimeout); + else if(!strncasecmp(buf,"framedivisor",strlen("framedivisor"))) + sscanf(buf,"%*s %d",&ServerConfig.FrameDivisor); + else if(!strncasecmp(buf,"port",strlen("port"))) + sscanf(buf,"%*s %d",&ServerConfig.Port); + else if(!strncasecmp(buf,"password",strlen("password"))) + { + char *pass = 0; + sscanf(buf,"%*s %as",&pass); + if(pass) + { + struct md5_context md5; + ServerConfig.Password = (uint8 *)malloc(16); + md5_starts(&md5); + md5_update(&md5,(uint8*)pass,strlen(pass)); + md5_finish(&md5,ServerConfig.Password); + puts("Password required to log in."); + } + } + } + } + + else + { + printf("Cannot load configuration file %s.\n", fn); + return(0); + } + + if(~0 == (ServerConfig.Port & ServerConfig.MaxClients & ServerConfig.ConnectTimeout & ServerConfig.FrameDivisor)) + { + puts("Incomplete configuration file"); + return(0); + } + //printf("%d,%d,%d\n",ServerConfig.MaxClients,ServerConfig.ConnectTimeout,ServerConfig.FrameDivisor); + printf("Using configuration file located at %s\n", fn); + return(1); +} + +static ClientEntry *Clients; +static GameEntry *Games; + +static void en32(uint8 *buf, uint32 morp) +{ + buf[0]=morp; + buf[1]=morp>>8; + buf[2]=morp>>16; + buf[3]=morp>>24; +} + +static uint32 de32(uint8 *morp) +{ + return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24)); +} + +static char *CleanNick(char *nick); +static int NickUnique(ClientEntry *client); +static void AddClientToGame(ClientEntry *client, uint8 id[16], uint8 extra[64]) throw(int); +static void SendToAll(GameEntry *game, int cmd, uint8 *data, uint32 len) throw(int); +static void BroadcastText(GameEntry *game, const char *fmt, ...) throw(int); +static void TextToClient(ClientEntry *client, const char *fmt, ...) throw(int); +static void KillClient(ClientEntry *client); + +#define NBTCP_LOGINLEN 0x100 +#define NBTCP_LOGIN 0x200 +#define NBTCP_COMMANDLEN 0x300 +#define NBTCP_COMMAND 0x400 + +#define NBTCP_UPDATEDATA 0x800 + +static void StartNBTCPReceive(ClientEntry *client, uint32 type, uint32 len) +{ + client->nbtcp = (uint8 *)malloc(len); + client->nbtcplen = len; + client->nbtcphas = 0; + client->nbtcptype = type; +} + +static void RedoNBTCPReceive(ClientEntry *client) +{ + client->nbtcphas = 0; +} + +static void EndNBTCPReceive(ClientEntry *client) +{ + free(client->nbtcp); + client->nbtcplen = client->localplayers; + client->nbtcphas = 0; + client->nbtcptype = 0; + client->nbtcp = 0; +} + +static uint8 *MakeMPS(ClientEntry *client) +{ + static uint8 buf[64]; + uint8 *bp = buf; + int x; + GameEntry *game = (GameEntry *)client->game; + + for(x=0;x<4;x++) + { + if(game->Players[x] == client) + { + *bp = '0' + x + 1; + bp++; + *bp = ','; + bp++; + } + } + if(*(bp-1) == ',') bp--; + + *bp = 0; + return(buf); +} + +/* Returns 1 if we are back to normal game mode, 0 if more data is yet to arrive. */ +static int CheckNBTCPReceive(ClientEntry *client) throw(int) +{ + if(!client->nbtcplen) + throw(1); /* Should not happen. */ + int l; + + while(l = recv(client->TCPSocket, client->nbtcp + client->nbtcphas, client->nbtcplen - client->nbtcphas, MSG_NOSIGNAL)) + { + if(l == -1) + { + if(errno == EAGAIN || errno == EWOULDBLOCK) + break; + throw(1); /* Die now. NOW. */ + } + client->nbtcphas += l; + + //printf("Read: %d, %04x, %d, %d\n",l,client->nbtcptype,client->nbtcphas, client->nbtcplen); + + /* We're all full. Yippie. */ + if(client->nbtcphas == client->nbtcplen) + { + uint32 len; + + switch(client->nbtcptype & 0xF00) + { + case NBTCP_UPDATEDATA: + { + GameEntry *game = (GameEntry *)client->game; + int x, wx; + if(client->nbtcp[0] == 0xFF) + { + EndNBTCPReceive(client); + StartNBTCPReceive(client, NBTCP_COMMANDLEN, 5); + return(1); + } + for(x=0,wx=0; x < 4; x++) + { + if(game->Players[x] == client) + { + game->joybuf[x] = client->nbtcp[wx]; + wx++; + } + } + RedoNBTCPReceive(client); + } + return(1); + case NBTCP_COMMANDLEN: + { + uint8 cmd = client->nbtcp[4]; + len = de32(client->nbtcp); + if(len > 200000) /* Sanity check. */ + throw(1); + + //printf("%02x, %d\n",cmd,len); + if(!len && !(cmd&0x80)) + { + SendToAll((GameEntry*)client->game, client->nbtcp[4], 0, 0); + EndNBTCPReceive(client); + StartNBTCPReceive(client,NBTCP_UPDATEDATA,client->localplayers); + } + else if(client->nbtcp[4]&0x80) + { + EndNBTCPReceive(client); + if(len) + StartNBTCPReceive(client,NBTCP_COMMAND | cmd,len); + else /* Woops. Client probably tried to send a text message of 0 length. Or maybe a 0-length cheat file? Better be safe! */ + StartNBTCPReceive(client,NBTCP_UPDATEDATA,client->localplayers); + } + else throw(1); + return(1); + } + case NBTCP_COMMAND: + { + len = client->nbtcplen; + uint32 tocmd = client->nbtcptype & 0xFF; + + if(tocmd == 0x90) /* Text */ + { + char *ma, *ma2; + + ma = (char *) malloc(len + 1); + memcpy(ma, client->nbtcp, len); + ma[len] = 0; + asprintf(&ma2, "<%s> %s",client->nickname,ma); + free(ma); + ma = ma2; + len=strlen(ma); + SendToAll((GameEntry*)client->game, tocmd, (uint8 *)ma, len); + free(ma); + } + else + SendToAll((GameEntry*)client->game, tocmd, client->nbtcp, len); + EndNBTCPReceive(client); + StartNBTCPReceive(client,NBTCP_UPDATEDATA,client->localplayers); + return(1); + } + case NBTCP_LOGINLEN:len = de32(client->nbtcp); + if(len > 1024 || len < (16 + 16 + 64 + 1)) + throw(1); + EndNBTCPReceive(client); + StartNBTCPReceive(client,NBTCP_LOGIN,len); + return(1); + case NBTCP_LOGIN: + { + uint32 len; + uint8 gameid[16]; + uint8 *sexybuf; + uint8 extra[64]; + + len = client->nbtcplen; + sexybuf = client->nbtcp; + + /* Game ID(MD5'd game MD5 and password on client side). */ + memcpy(gameid, sexybuf, 16); + sexybuf += 16; + len -= 16; + + if(ServerConfig.Password) + if(memcmp(ServerConfig.Password,sexybuf,16)) + { + TextToClient(client,"Invalid server password."); + throw(1); + } + sexybuf += 16; + len -= 16; + + memcpy(extra, sexybuf, 64); + sexybuf += 64; + len -= 64; + + client->localplayers = *sexybuf; + if(client->localplayers < 1 || client->localplayers > 4) + { + TextToClient(client,"Invalid number(%d) of local players!",client->localplayers); + throw(1); + } + sexybuf++; + len -= 1; + + AddClientToGame(client, gameid, extra); + /* Get the nickname */ + if(len) + { + client->nickname = (char *)malloc(len + 1); + memcpy(client->nickname, sexybuf, len); + client->nickname[len] = 0; + if((client->nickname = CleanNick(client->nickname))) + if(!NickUnique(client)) /* Nickname already exists */ + { + free(client->nickname); + client->nickname = 0; + } + } + uint8 *mps = MakeMPS(client); + + if(!client->nickname) + asprintf(&client->nickname,"*Player %s",mps); + + printf("Client %d assigned to game %d as player %s <%s>\n",client->id,(GameEntry*)client->game - Games,mps, client->nickname); + + int x; + GameEntry *tg=(GameEntry *)client->game; + + for(x=0; xMaxPlayers; x++) + if(tg->Players[x] && tg->IsUnique[x]) + { + if(tg->Players[x] != client) + { + try + { + TextToClient(tg->Players[x], "* Player %s has just connected as: %s",MakeMPS(client),client->nickname); + } catch(int i) + { + KillClient(tg->Players[x]); + } + TextToClient(client, "* Player %s is already connected as: %s",MakeMPS(tg->Players[x]),tg->Players[x]->nickname); + } + else + TextToClient(client, "* You(Player %s) have just connected as: %s",MakeMPS(client),client->nickname); + } + } + EndNBTCPReceive(client); + StartNBTCPReceive(client,NBTCP_UPDATEDATA,client->localplayers); + return(1); + } + } + } + return(0); +} + +int ListenSocket; + +static char *CleanNick(char *nick) +{ + int x; + + for(x=0; x' || nick[x] == '*' || (nick[x] < 0x20)) + nick[x] = 0; + if(!strlen(nick)) + { + free(nick); + nick = 0; + } + + return(nick); +} + +static int NickUnique(ClientEntry *client) +{ + int x; + GameEntry *game = (GameEntry *)client-> game; + + for(x=0; xMaxPlayers; x++) + if(game->Players[x] && client != game->Players[x]) + if(!strcasecmp(client->nickname, game->Players[x]->nickname)) + return(0); + return(1); +} + +static int MakeSendTCP(ClientEntry *client, uint8 *data, uint32 len) throw(int) +{ + if(send(client->TCPSocket, data, len, MSG_NOSIGNAL) != len) + throw(1); + return(1); +} + +static void SendToAll(GameEntry *game, int cmd, uint8 *data, uint32 len) throw(int) +{ + uint8 poo[5]; + int x; + + poo[4] = cmd; + + for(x=0;xMaxPlayers;x++) + { + if(!game->Players[x] || !game->IsUnique[x]) continue; + + try + { + if(cmd & 0x80) + en32(poo, len); + MakeSendTCP(game->Players[x],poo,5); + + if(cmd & 0x80) + { + MakeSendTCP(game->Players[x], data, len); + } + } + catch(int i) + { + KillClient(game->Players[x]); + } + + } +} + +static void TextToClient(ClientEntry *client, const char *fmt, ...) throw(int) +{ + char *moo; + va_list ap; + + va_start(ap,fmt); + vasprintf(&moo, fmt, ap); + va_end(ap); + + + uint8 poo[5]; + uint32 len; + + poo[4] = 0x90; + len = strlen(moo); + en32(poo, len); + + MakeSendTCP(client, poo, 5); + MakeSendTCP(client, (uint8*)moo, len); + free(moo); +} + +static void BroadcastText(GameEntry *game, const char *fmt, ...) throw(int) +{ + char *moo; + va_list ap; + + va_start(ap,fmt); + vasprintf(&moo, fmt, ap); + va_end(ap); + + SendToAll(game, 0x90,(uint8 *)moo,strlen(moo)); + free(moo); +} + +static void KillClient(ClientEntry *client) +{ + GameEntry *game; + uint8 *mps; + char *bmsg; + + game = (GameEntry *)client->game; + if(game) + { + int w; + int tc = 0; + + for(w=0;wMaxPlayers;w++) + if(game->Players[w]) tc++; + + for(w=0;wMaxPlayers;w++) + if(game->Players[w]) + if(game->Players[w] == client) + game->Players[w] = NULL; + + time_t curtime = time(0); + printf("Player <%s> disconnected from game %d on %s",client->nickname,game-Games,ctime(&curtime)); + asprintf(&bmsg, "* Player %s <%s> left.",MakeMPS(client),client->nickname); + if(tc == client->localplayers) /* If total players for this game = total local + players for this client, destroy the game. + */ + { + printf("Game %d destroyed.\n",game-Games); + memset(game, 0, sizeof(GameEntry)); + game = 0; + } + } + else + { + time_t curtime = time(0); + printf("Unassigned client %d disconnected on %s",client->id, ctime(&curtime)); + } + if(client->nbtcp) + free(client->nbtcp); + + if(client->nickname) + free(client->nickname); + + if(client->TCPSocket != -1) + close(client->TCPSocket); + memset(client, 0, sizeof(ClientEntry)); + client->TCPSocket = -1; + + if(game) + BroadcastText(game,"%s",bmsg); +} + +static void AddClientToGame(ClientEntry *client, uint8 id[16], uint8 extra[64]) throw(int) +{ + int wg; + GameEntry *game,*fegame; + + retry: + + game = NULL; + fegame = NULL; + + /* First, find an available game. */ + for(wg=0; wgMaxPlayers = 4; + memcpy(game->id, id, 16); + memcpy(game->ExtraInfo, extra, 64); + } + + + int n; + for(n = 0; n < game->MaxPlayers; n++) + if(game->Players[n]) + { + try + { + uint8 b[5]; + b[4] = 0x81; + MakeSendTCP(game->Players[n], b, 5); + break; + } + catch(int i) + { + KillClient(game->Players[n]); + /* All right, now the client we sent the request to is killed. I HOPE YOU'RE HAPPY! */ + /* Since killing a client can destroy a game, we'll need to see if the game was trashed. + If it was, then "goto retry", and try again. Ugly, yes. I LIKE UGLY. + */ + if(!game->MaxPlayers) + goto retry; + } + } + + int instancecount = client->localplayers; + + for(n=0; nMaxPlayers; n++) + if(!game->Players[n]) + { + game->Players[n] = client; + if(instancecount == client->localplayers) + game->IsUnique[n] = 1; + else + game->IsUnique[n] = 0; + instancecount --; + if(!instancecount) + break; + } + + /* Game is full. */ + if(n == game->MaxPlayers) + { + for(n=0; nMaxPlayers; n++) + if(game->Players[n] == client) + game->Players[n] = 0; + TextToClient(client, "Sorry, game is full. %d instance(s) tried, %d available.",client->localplayers,client->localplayers - instancecount); + throw(1); + } + + client->game = (void *)game; +} + + + + +int main(int argc, char *argv[]) +{ + + struct sockaddr_in sockin; + socklen_t sockin_len; + int i; + char* pass = 0; + /* If we can't load the default config file, use some defined values */ + if(!LoadConfigFile(DEFAULT_CONFIG)) { + ServerConfig.Port = DEFAULT_PORT; + ServerConfig.MaxClients = DEFAULT_MAX; + ServerConfig.ConnectTimeout = DEFAULT_TIMEOUT; + ServerConfig.FrameDivisor = DEFAULT_FRAMEDIVISOR; + } + char* configfile = 0; + + + for(i=1; ilocalplayers; + + while(CheckNBTCPReceive(client)) {}; + } // catch + catch(int i) + { + KillClient(Games[whichgame].Players[n]); + } + } // A games clients + + /* Now we send the data to all the clients. */ + for(n = 0; n < Games[whichgame].MaxPlayers; n++) + { + if(!Games[whichgame].Players[n] || !Games[whichgame].IsUnique[n]) continue; + try + { + MakeSendTCP(Games[whichgame].Players[n], Games[whichgame].joybuf, 5); + } + catch(int i) + { + KillClient(Games[whichgame].Players[n]); + } + } // A game's clients + } // Games + + SpeedThrottle(); + } // while(1) +} diff --git a/fceu-server/throttle.cpp b/fceu-server/throttle.cpp new file mode 100644 index 00000000..846f3e8f --- /dev/null +++ b/fceu-server/throttle.cpp @@ -0,0 +1,102 @@ +/* FCE Ultra Network Play Server + * + * Copyright notice for this file: + * Copyright (C) 2004 Xodnizel + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + + +#include +#include +#include "types.h" +#include "throttle.h" + +#ifdef TODO +THROTTLE *MakeThrottle(uint32 fps) +{ + + +} + +/* Returns 1 if it's time to run, 0 if it's not time yet. */ +int TestThrottle(THROTTLE *throt) +{ + +} + +/* Pass it a pointer to an array of THROTTLE structs */ +/* It will check */ +void DoAllThrottles(THROTTLE *throt) +{ + + +} + +void KillThrottle(THROTTLE *throt) +{ + +} + +#endif + +static uint64 tfreq; +static uint64 desiredfps; + +int32 FCEUI_GetDesiredFPS(void) +{ + //if(PAL) + // return(838977920); // ~50.007 + //else + return(1008307711); // ~60.1 +} + +void RefreshThrottleFPS(int divooder) +{ + desiredfps=(FCEUI_GetDesiredFPS() / divooder)>>8; + tfreq=1000000; + tfreq<<=16; /* Adjustment for fps returned from FCEUI_GetDesiredFPS(). */ +} + +static uint64 GetCurTime(void) +{ + uint64 ret; + struct timeval tv; + + gettimeofday(&tv,0); + ret=(uint64)tv.tv_sec*1000000; + ret+=tv.tv_usec; + return(ret); +} + +void SpeedThrottle(void) +{ + static uint64 ttime,ltime; + + waiter: + ttime=GetCurTime(); + + if( (ttime-ltime) < (tfreq/desiredfps) ) + { + usleep(1000); + goto waiter; + } + if( (ttime-ltime) >= (tfreq*4/desiredfps)) + ltime=ttime; + else + ltime+=tfreq/desiredfps; +} + diff --git a/fceu-server/throttle.h b/fceu-server/throttle.h new file mode 100644 index 00000000..b8357b56 --- /dev/null +++ b/fceu-server/throttle.h @@ -0,0 +1,23 @@ +/* FCE Ultra Network Play Server + * + * Copyright notice for this file: + * Copyright (C) 2004 Xodnizel + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * */ + + +void RefreshThrottleFPS(int divooder); +void SpeedThrottle(void); diff --git a/fceu-server/types.h b/fceu-server/types.h new file mode 100644 index 00000000..7b831930 --- /dev/null +++ b/fceu-server/types.h @@ -0,0 +1,38 @@ +/* FCE Ultra Network Play Server + * + * Copyright notice for this file: + * Copyright (C) 2004 Xodnizel + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __FCEU_TYPES +#define __FCEU_TYPES + +#include +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; + +typedef unsigned long long uint64; +typedef long long int64; +#define INLINE inline +#define GINLINE inline + +#endif