diff --git a/README.md b/README.md index bfdbce5..343fef1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,21 @@ # GrowtopiaServer First Growtopia Private Server made with ENet. + +This project has been compiled with Visual Studio 2015 (Visual Studio 2013 or older won't work!) and newer versions of VS or other compilers weren't been tested. + +This project has been published under GNU AFFERO GPL license, so you need to **publish whole source code and citate orginal authors name, even if you are using your server as service**! + +**TODO list:** +1. Refactor whole code, it is very hard readable and there might be problems with maintaining it +2. Try get some normal DB working or atleast save all files as BSON or some binary format +3. Write load balancer, it is very CPU expensive part because it calculates BCrypt hashes and access to database +4. Try possible to write multiple servers which only share between themselves possibly world list, player list and boradcast queue +5. Extend data which are saved now - there should be saved current clothes, inventory, login time, register time and maybe tracing hashes if you want to do proper ban system also in worlds there should be saved block extras (enabled, water, fire, etc.) and dropped items +6. Write event pool - this is needed to make delayed actions like respawning +7. Make heavy events asynchronous with possibly some good thread count (probably one or two) and connect them to event pool or use callbacks +8. Daily news (Growtopia Gazzete) should be saved to external file and not in source for easier modifying +9. Disable all loging to console and log everything to file, this will free up console for CLI + +If you want to support development of this server, then make sure you contribute to this repo! + +Make that sure that you subscribe my channel https://www.youtube.com/channel/UCLXtuoBlrXFDRtFU8vPy35g and enjoy :+1: \ No newline at end of file diff --git a/enet server test.sln b/enet server test.sln new file mode 100644 index 0000000..59ebab9 --- /dev/null +++ b/enet server test.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "enet server test", "enet server test\enet server test.vcxproj", "{0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Debug|Win32.Build.0 = Debug|Win32 + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Debug|x64.ActiveCfg = Debug|x64 + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Debug|x64.Build.0 = Debug|x64 + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Release|Win32.ActiveCfg = Release|Win32 + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Release|Win32.Build.0 = Release|Win32 + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Release|x64.ActiveCfg = Release|x64 + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/enet server test/ReadMe.txt b/enet server test/ReadMe.txt new file mode 100644 index 0000000..7da2ff0 --- /dev/null +++ b/enet server test/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : enet server test Project Overview +======================================================================== + +AppWizard has created this enet server test application for you. + +This file contains a summary of what you will find in each of the files that +make up your enet server test application. + + +enet server test.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +enet server test.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +enet server test.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named enet server test.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/enet server test/bcrypt.c b/enet server test/bcrypt.c new file mode 100644 index 0000000..74f4b81 --- /dev/null +++ b/enet server test/bcrypt.c @@ -0,0 +1,206 @@ +/* + * bcrypt wrapper library + * + * Written in 2011, 2013, 2014, 2015 by Ricardo Garcia + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ +#include +#include +#include +#include +//#include +#ifndef _UNISTD_H +#define _UNISTD_H 1 + +/* This is intended as a drop-in replacement for unistd.h on Windows. +* Please add functionality as neeeded. +* https://stackoverflow.com/a/826027/1202830 +*/ + +#include +#include +//#include /* getopt at: https://gist.github.com/ashelly/7776712 */ +#include /* for getpid() and the exec..() family */ +#include /* for _getcwd() and _chdir() */ + +#define srandom srand +#define random rand + +/* Values for the second argument to access. +These may be OR'd together. */ +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +//#define X_OK 1 /* execute permission - unsupported in windows*/ +#define F_OK 0 /* Test for existence. */ + +#define access _access +#define dup2 _dup2 +#define execve _execve +#define ftruncate _chsize +#define unlink _unlink +#define fileno _fileno +#define getcwd _getcwd +#define chdir _chdir +#define isatty _isatty +#define lseek _lseek +/* read, write, and close are NOT being #defined here, because while there are file handle specific versions for Windows, they probably don't work for sockets. You need to look at your app and consider whether to call e.g. closesocket(). */ + +#ifdef _WIN64 +#define ssize_t __int64 +#else +#define ssize_t long +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +/* should be in some equivalent to */ +//typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#endif /* unistd.h */ + +#include + +#include "bcrypt.h" +#include "crypt_blowfish/ow-crypt.h" + +#define RANDBYTES (16) + +/* + * This is a best effort implementation. Nothing prevents a compiler from + * optimizing this function and making it vulnerable to timing attacks, but + * this method is commonly used in crypto libraries like NaCl. + * + * Return value is zero if both strings are equal and nonzero otherwise. +*/ +static int timing_safe_strcmp(const char *str1, const char *str2) +{ + const unsigned char *u1; + const unsigned char *u2; + int ret; + int i; + + int len1 = strlen(str1); + int len2 = strlen(str2); + + /* In our context both strings should always have the same length + * because they will be hashed passwords. */ + if (len1 != len2) + return 1; + + /* Force unsigned for bitwise operations. */ + u1 = (const unsigned char *)str1; + u2 = (const unsigned char *)str2; + + ret = 0; + for (i = 0; i < len1; ++i) + ret |= (u1[i] ^ u2[i]); + + return ret; +} + +int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE]) +{ + int fd; + char input[RANDBYTES]; + int workf; + char *aux; + + for (int i = 0; i < RANDBYTES; i++) + { + input[i] = rand(); + } + + /* Generate salt. */ + workf = (factor < 4 || factor > 31)?12:factor; + aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES, + salt, BCRYPT_HASHSIZE); + return (aux == NULL)?5:0; +} + +int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) +{ + char *aux; + aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE); + return (aux == NULL)?1:0; +} + +int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]) +{ + int ret; + char outhash[BCRYPT_HASHSIZE]; + + ret = bcrypt_hashpw(passwd, hash, outhash); + if (ret != 0) + return -1; + + return timing_safe_strcmp(hash, outhash); +} + +#ifdef TEST_BCRYPT +#include +#include +#include +#include + +int main(void) +{ + clock_t before; + clock_t after; + char salt[BCRYPT_HASHSIZE]; + char hash[BCRYPT_HASHSIZE]; + int ret; + + const char pass[] = "hi,mom"; + const char hash1[] = "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK"; + const char hash2[] = "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO"; + + ret = bcrypt_gensalt(12, salt); + assert(ret == 0); + printf("Generated salt: %s\n", salt); + before = clock(); + ret = bcrypt_hashpw("testtesttest", salt, hash); + assert(ret == 0); + after = clock(); + printf("Hashed password: %s\n", hash); + printf("Time taken: %f seconds\n", + (double)(after - before) / CLOCKS_PER_SEC); + + ret = bcrypt_hashpw(pass, hash1, hash); + assert(ret == 0); + printf("First hash check: %s\n", (strcmp(hash1, hash) == 0)?"OK":"FAIL"); + ret = bcrypt_hashpw(pass, hash2, hash); + assert(ret == 0); + printf("Second hash check: %s\n", (strcmp(hash2, hash) == 0)?"OK":"FAIL"); + + before = clock(); + ret = (bcrypt_checkpw(pass, hash1) == 0); + after = clock(); + printf("First hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL"); + printf("Time taken: %f seconds\n", + (double)(after - before) / CLOCKS_PER_SEC); + + before = clock(); + ret = (bcrypt_checkpw(pass, hash2) == 0); + after = clock(); + printf("Second hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL"); + printf("Time taken: %f seconds\n", + (double)(after - before) / CLOCKS_PER_SEC); + + return 0; +} +#endif diff --git a/enet server test/bcrypt.h b/enet server test/bcrypt.h new file mode 100644 index 0000000..e45b3ca --- /dev/null +++ b/enet server test/bcrypt.h @@ -0,0 +1,97 @@ +#ifndef BCRYPT_H_ +#define BCRYPT_H_ +/* + * bcrypt wrapper library + * + * Written in 2011, 2013, 2014, 2015 by Ricardo Garcia + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#define BCRYPT_HASHSIZE (64) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This function expects a work factor between 4 and 31 and a char array to + * store the resulting generated salt. The char array should typically have + * BCRYPT_HASHSIZE bytes at least. If the provided work factor is not in the + * previous range, it will default to 12. + * + * The return value is zero if the salt could be correctly generated and + * nonzero otherwise. + * + */ +int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]); + +/* + * This function expects a password to be hashed, a salt to hash the password + * with and a char array to leave the result. Both the salt and the hash + * parameters should have room for BCRYPT_HASHSIZE characters at least. + * + * It can also be used to verify a hashed password. In that case, provide the + * expected hash in the salt parameter and verify the output hash is the same + * as the input hash. However, to avoid timing attacks, it's better to use + * bcrypt_checkpw when verifying a password. + * + * The return value is zero if the password could be hashed and nonzero + * otherwise. + */ +int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], + char hash[BCRYPT_HASHSIZE]); + +/* + * This function expects a password and a hash to verify the password against. + * The internal implementation is tuned to avoid timing attacks. + * + * The return value will be -1 in case of errors, zero if the provided password + * matches the given hash and greater than zero if no errors are found and the + * passwords don't match. + * + */ +int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]); + +/* + * Brief Example + * ------------- + * + * Hashing a password: + * + * char salt[BCRYPT_HASHSIZE]; + * char hash[BCRYPT_HASHSIZE]; + * int ret; + * + * ret = bcrypt_gensalt(12, salt); + * assert(ret == 0); + * ret = bcrypt_hashpw("thepassword", salt, hash); + * assert(ret == 0); + * + * + * Verifying a password: + * + * int ret; + * + * ret = bcrypt_checkpw("thepassword", "expectedhash"); + * assert(ret != -1); + * + * if (ret == 0) { + * printf("The password matches\n"); + * } else { + * printf("The password does NOT match\n"); + * } + * + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/enet server test/crypt_blowfish/LINKS b/enet server test/crypt_blowfish/LINKS new file mode 100644 index 0000000..a6cb7e1 --- /dev/null +++ b/enet server test/crypt_blowfish/LINKS @@ -0,0 +1,29 @@ +New versions of this package (crypt_blowfish): + + http://www.openwall.com/crypt/ + +A paper on the algorithm that explains its design decisions: + + http://www.usenix.org/events/usenix99/provos.html + +Unix Seventh Edition Manual, Volume 2: the password scheme (1978): + + http://plan9.bell-labs.com/7thEdMan/vol2/password + +The Openwall GNU/*/Linux (Owl) tcb suite implementing the alternative +password shadowing scheme. This includes a PAM module which +supersedes pam_unix and uses the password hashing framework provided +with crypt_blowfish when setting new passwords. + + http://www.openwall.com/tcb/ + +pam_passwdqc, a password strength checking and policy enforcement +module for PAM-aware password changing programs: + + http://www.openwall.com/passwdqc/ + +John the Ripper password cracker: + + http://www.openwall.com/john/ + +$Owl: Owl/packages/glibc/crypt_blowfish/LINKS,v 1.4 2005/11/16 13:09:47 solar Exp $ diff --git a/enet server test/crypt_blowfish/Makefile b/enet server test/crypt_blowfish/Makefile new file mode 100644 index 0000000..c162adc --- /dev/null +++ b/enet server test/crypt_blowfish/Makefile @@ -0,0 +1,77 @@ +# +# Written and revised by Solar Designer in 2000-2011. +# No copyright is claimed, and the software is hereby placed in the public +# domain. In case this attempt to disclaim copyright and place the software +# in the public domain is deemed null and void, then the software is +# Copyright (c) 2000-2011 Solar Designer and it is hereby released to the +# general public under the following terms: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted. +# +# There's ABSOLUTELY NO WARRANTY, express or implied. +# +# See crypt_blowfish.c for more information. +# + +CC = gcc +AS = $(CC) +LD = $(CC) +RM = rm -f +CFLAGS = -W -Wall -Wbad-function-cast -Wcast-align -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wundef -Wpointer-arith -O2 -fomit-frame-pointer -funroll-loops +ASFLAGS = -c +LDFLAGS = -s + +BLOWFISH_OBJS = \ + crypt_blowfish.o x86.o + +CRYPT_OBJS = \ + $(BLOWFISH_OBJS) crypt_gensalt.o wrapper.o + +TEST_OBJS = \ + $(BLOWFISH_OBJS) crypt_gensalt.o crypt_test.o + +TEST_THREADS_OBJS = \ + $(BLOWFISH_OBJS) crypt_gensalt.o crypt_test_threads.o + +EXTRA_MANS = \ + crypt_r.3 crypt_rn.3 crypt_ra.3 \ + crypt_gensalt.3 crypt_gensalt_rn.3 crypt_gensalt_ra.3 + +all: $(CRYPT_OBJS) man + +check: crypt_test + ./crypt_test + +crypt_test: $(TEST_OBJS) + $(LD) $(LDFLAGS) $(TEST_OBJS) -o $@ + +crypt_test.o: wrapper.c ow-crypt.h crypt_blowfish.h crypt_gensalt.h + $(CC) -c $(CFLAGS) wrapper.c -DTEST -o $@ + +check_threads: crypt_test_threads + ./crypt_test_threads + +crypt_test_threads: $(TEST_THREADS_OBJS) + $(LD) $(LDFLAGS) $(TEST_THREADS_OBJS) -lpthread -o $@ + +crypt_test_threads.o: wrapper.c ow-crypt.h crypt_blowfish.h crypt_gensalt.h + $(CC) -c $(CFLAGS) wrapper.c -DTEST -DTEST_THREADS=4 -o $@ + +man: $(EXTRA_MANS) + +$(EXTRA_MANS): + echo '.so man3/crypt.3' > $@ + +crypt_blowfish.o: crypt_blowfish.h +crypt_gensalt.o: crypt_gensalt.h +wrapper.o: crypt.h ow-crypt.h crypt_blowfish.h crypt_gensalt.h + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +.S.o: + $(AS) $(ASFLAGS) $*.S + +clean: + $(RM) crypt_test crypt_test_threads *.o $(EXTRA_MANS) core diff --git a/enet server test/crypt_blowfish/PERFORMANCE b/enet server test/crypt_blowfish/PERFORMANCE new file mode 100644 index 0000000..9d6fe4e --- /dev/null +++ b/enet server test/crypt_blowfish/PERFORMANCE @@ -0,0 +1,30 @@ +These numbers are for 32 iterations ("$2a$05"): + + OpenBSD 3.0 bcrypt(*) crypt_blowfish 0.4.4 +Pentium III, 840 MHz 99 c/s 121 c/s (+22%) +Alpha 21164PC, 533 MHz 55.5 c/s 76.9 c/s (+38%) +UltraSparc IIi, 400 MHz 49.9 c/s 52.5 c/s (+5%) +Pentium, 120 MHz 8.8 c/s 20.1 c/s (+128%) +PA-RISC 7100LC, 80 MHz 8.5 c/s 16.3 c/s (+92%) + +(*) built with -fomit-frame-pointer -funroll-loops, which I don't +think happens for libcrypt. + +Starting with version 1.1 released in June 2011, default builds of +crypt_blowfish invoke a quick self-test on every hash computation. +This has roughly a 4.8% performance impact at "$2a$05", but only a 0.6% +impact at a more typical setting of "$2a$08". + +The large speedup for the original Pentium is due to the assembly +code and the weird optimizations this processor requires. + +The numbers for password cracking are 2 to 10% higher than those for +crypt_blowfish as certain things may be done out of the loop and the +code doesn't need to be reentrant. + +Recent versions of John the Ripper (1.6.25-dev and newer) achieve an +additional 15% speedup on the Pentium Pro family of processors (which +includes Pentium III) with a separate version of the assembly code and +run-time CPU detection. + +$Owl: Owl/packages/glibc/crypt_blowfish/PERFORMANCE,v 1.6 2011/06/21 12:09:20 solar Exp $ diff --git a/enet server test/crypt_blowfish/README b/enet server test/crypt_blowfish/README new file mode 100644 index 0000000..e95da23 --- /dev/null +++ b/enet server test/crypt_blowfish/README @@ -0,0 +1,68 @@ +This is an implementation of a password hashing method, provided via the +crypt(3) and a reentrant interface. It is fully compatible with +OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and +David Mazieres. (Please refer to the included crypt(3) man page for +information on minor compatibility issues for other bcrypt prefixes.) + +I've placed this code in the public domain, with fallback to a +permissive license. Please see the comment in crypt_blowfish.c for +more information. + +You can use the provided routines in your own packages, or link them +into a C library. I've provided hooks for linking into GNU libc, but +it shouldn't be too hard to get this into another C library. Note +that simply adding this code into your libc is probably not enough to +make your system use the new password hashing algorithm. Changes to +passwd(1), PAM modules, or whatever else your system uses will likely +be needed as well. These are not a part of this package, but see +LINKS for a pointer to our tcb suite. + +Instructions on using the routines in one of the two common ways are +given below. It is recommended that you test the routines on your +system before you start. Type "make check" or "make check_threads" +(if you have the POSIX threads library), then "make clean". + + +1. Using the routines in your programs. + +The available interfaces are in ow-crypt.h, and this is the file you +should include. You won't need crypt.h. When linking, add all of the +C files and x86.S (you can compile and link it even on a non-x86, it +will produce no code in this case). + + +2. Building the routines into GNU C library. + +For versions 2.13 and 2.14 (and likely other nearby ones), extract the +library sources as usual. Apply the patch for glibc 2.14 provided in +this package. Enter crypt/ and rename crypt.h to gnu-crypt.h within +that directory. Copy the C sources, header, and assembly (x86.S) files +from this package in there as well (but be sure you don't overwrite the +Makefile). Configure, build, and install the library as usual. + +For versions 2.2 to 2.3.6 (and likely also for some newer ones), +extract the library sources and maybe its optional add-ons as usual. +Apply the patch for glibc 2.3.6 provided in this package. Enter +crypt/ and rename crypt.h to gnu-crypt.h within that directory. Copy +the C sources, header, and assembly (x86.S) files from this package in +there as well (but be sure you don't overwrite the Makefile). +Configure, build, and install the library as usual. + +For versions 2.1 to 2.1.3, extract the library sources and the crypt +and linuxthreads add-ons as usual. Apply the patch for glibc 2.1.3 +provided in this package. Enter crypt/sysdeps/unix/, and rename +crypt.h to gnu-crypt.h within that directory. Copy C sources, header, +and assembly (x86.S) files from this package in there as well (but be +sure you don't overwrite the Makefile). Configure, build, and install +the library as usual. + +Programs that want to use the provided interfaces will need to include +crypt.h (but not ow-crypt.h directly). By default, prototypes for the +new routines aren't defined (but the extra functionality of crypt(3) +is indeed available). You need to define _OW_SOURCE to obtain the new +routines as well. + +-- +Solar Designer + +$Owl: Owl/packages/glibc/crypt_blowfish/README,v 1.10 2014/07/07 15:19:04 solar Exp $ diff --git a/enet server test/crypt_blowfish/crypt.3 b/enet server test/crypt_blowfish/crypt.3 new file mode 100644 index 0000000..b4c0895 --- /dev/null +++ b/enet server test/crypt_blowfish/crypt.3 @@ -0,0 +1,575 @@ +.\" Written and revised by Solar Designer in 2000-2011. +.\" No copyright is claimed, and this man page is hereby placed in the public +.\" domain. In case this attempt to disclaim copyright and place the man page +.\" in the public domain is deemed null and void, then the man page is +.\" Copyright (c) 2000-2011 Solar Designer and it is hereby released to the +.\" general public under the following terms: +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted. +.\" +.\" There's ABSOLUTELY NO WARRANTY, express or implied. +.\" +.\" This manual page in its current form is intended for use on systems +.\" based on the GNU C Library with crypt_blowfish patched into libcrypt. +.\" +.TH CRYPT 3 "July 7, 2014" "Openwall Project" "Library functions" +.ad l +.\" No macros in NAME to keep makewhatis happy. +.SH NAME +\fBcrypt\fR, \fBcrypt_r\fR, \fBcrypt_rn\fR, \fBcrypt_ra\fR, +\fBcrypt_gensalt\fR, \fBcrypt_gensalt_rn\fR, \fBcrypt_gensalt_ra\fR +\- password hashing +.SH SYNOPSIS +.B #define _XOPEN_SOURCE +.br +.B #include +.sp +.in +8 +.ti -8 +.BI "char *crypt(const char *" key ", const char *" setting ); +.in -8 +.sp +.B #define _GNU_SOURCE +.br +.B #include +.sp +.in +8 +.ti -8 +.BI "char *crypt_r(const char *" key ", const char *" setting ", struct crypt_data *" data ); +.in -8 +.sp +.B #define _OW_SOURCE +.br +.B #include +.sp +.in +8 +.ti -8 +.BI "char *crypt_rn(const char *" key ", const char *" setting ", void *" data ", int " size ); +.ti -8 +.BI "char *crypt_ra(const char *" key ", const char *" setting ", void **" data ", int *" size ); +.ti -8 +.BI "char *crypt_gensalt(const char *" prefix ", unsigned long " count ", const char *" input ", int " size ); +.ti -8 +.BI "char *crypt_gensalt_rn(const char *" prefix ", unsigned long " count ", const char *" input ", int " size ", char *" output ", int " output_size ); +.ti -8 +.BI "char *crypt_gensalt_ra(const char *" prefix ", unsigned long " count ", const char *" input ", int " size ); +.ad b +.de crypt +.BR crypt , +.BR crypt_r , +.BR crypt_rn ", \\$1" +.ie "\\$2"" .B crypt_ra +.el .BR crypt_ra "\\$2" +.. +.de crypt_gensalt +.BR crypt_gensalt , +.BR crypt_gensalt_rn ", \\$1" +.ie "\\$2"" .B crypt_gensalt_ra +.el .BR crypt_gensalt_ra "\\$2" +.. +.SH DESCRIPTION +The +.crypt and +functions calculate a cryptographic hash function of +.I key +with one of a number of supported methods as requested with +.IR setting , +which is also used to pass a salt and possibly other parameters to +the chosen method. +The hashing methods are explained below. +.PP +Unlike +.BR crypt , +the functions +.BR crypt_r , +.BR crypt_rn " and" +.B crypt_ra +are reentrant. +They place their result and possibly their private data in a +.I data +area of +.I size +bytes as passed to them by an application and/or in memory they +allocate dynamically. Some hashing algorithms may use the data area to +cache precomputed intermediate values across calls. Thus, applications +must properly initialize the data area before its first use. +.B crypt_r +requires that only +.I data->initialized +be reset to zero; +.BR crypt_rn " and " crypt_ra +require that either the entire data area is zeroed or, in the case of +.BR crypt_ra , +.I *data +is NULL. When called with a NULL +.I *data +or insufficient +.I *size +for the requested hashing algorithm, +.B crypt_ra +uses +.BR realloc (3) +to allocate the required amount of memory dynamically. Thus, +.B crypt_ra +has the additional requirement that +.IR *data , +when non-NULL, must point to an area allocated either with a previous +call to +.B crypt_ra +or with a +.BR malloc (3) +family call. +The memory allocated by +.B crypt_ra +should be freed with +.BR free "(3)." +.PP +The +.crypt_gensalt and +functions compile a string for use as +.I setting +\- with the given +.I prefix +(used to choose a hashing method), the iteration +.I count +(if supported by the chosen method) and up to +.I size +cryptographically random +.I input +bytes for use as the actual salt. +If +.I count +is 0, a low default will be picked. +The random bytes may be obtained from +.BR /dev/urandom . +Unlike +.BR crypt_gensalt , +the functions +.BR crypt_gensalt_rn " and " crypt_gensalt_ra +are reentrant. +.B crypt_gensalt_rn +places its result in the +.I output +buffer of +.I output_size +bytes. +.B crypt_gensalt_ra +allocates memory for its result dynamically. The memory should be +freed with +.BR free "(3)." +.SH RETURN VALUE +Upon successful completion, the functions +.crypt and +return a pointer to a string containing the setting that was actually used +and a printable encoding of the hash function value. +The entire string is directly usable as +.I setting +with other calls to +.crypt and +and as +.I prefix +with calls to +.crypt_gensalt and . +.PP +The behavior of +.B crypt +on errors isn't well standardized. Some implementations simply can't fail +(unless the process dies, in which case they obviously can't return), +others return NULL or a fixed string. Most implementations don't set +.IR errno , +but some do. SUSv2 specifies only returning NULL and setting +.I errno +as a valid behavior, and defines only one possible error +.RB "(" ENOSYS , +"The functionality is not supported on this implementation.") +Unfortunately, most existing applications aren't prepared to handle +NULL returns from +.BR crypt . +The description below corresponds to this implementation of +.BR crypt " and " crypt_r +only, and to +.BR crypt_rn " and " crypt_ra . +The behavior may change to match standards, other implementations or +existing applications. +.PP +.BR crypt " and " crypt_r +may only fail (and return) when passed an invalid or unsupported +.IR setting , +in which case they return a pointer to a magic string that is +shorter than 13 characters and is guaranteed to differ from +.IR setting . +This behavior is safe for older applications which assume that +.B crypt +can't fail, when both setting new passwords and authenticating against +existing password hashes. +.BR crypt_rn " and " crypt_ra +return NULL to indicate failure. All four functions set +.I errno +when they fail. +.PP +The functions +.crypt_gensalt and +return a pointer to the compiled string for +.IR setting , +or NULL on error in which case +.I errno +is set. +.SH ERRORS +.TP +.B EINVAL +.crypt "" : +.I setting +is invalid or not supported by this implementation; +.sp +.crypt_gensalt "" : +.I prefix +is invalid or not supported by this implementation; +.I count +is invalid for the requested +.IR prefix ; +the input +.I size +is insufficient for the smallest valid salt with the requested +.IR prefix ; +.I input +is NULL. +.TP +.B ERANGE +.BR crypt_rn : +the provided data area +.I size +is insufficient for the requested hashing algorithm; +.sp +.BR crypt_gensalt_rn : +.I output_size +is too small to hold the compiled +.I setting +string. +.TP +.B ENOMEM +.B crypt +(original glibc only): +failed to allocate memory for the output buffer (which subsequent calls +would re-use); +.sp +.BR crypt_ra : +.I *data +is NULL or +.I *size +is insufficient for the requested hashing algorithm and +.BR realloc (3) +failed; +.sp +.BR crypt_gensalt_ra : +failed to allocate memory for the compiled +.I setting +string. +.TP +.B ENOSYS +.B crypt +(SUSv2): +the functionality is not supported on this implementation; +.sp +.BR crypt , +.B crypt_r +(glibc 2.0 to 2.0.1 only): +.de no-crypt-add-on +the crypt add-on is not compiled in and +.I setting +requests something other than the MD5-based algorithm. +.. +.no-crypt-add-on +.TP +.B EOPNOTSUPP +.BR crypt , +.B crypt_r +(glibc 2.0.2 to 2.1.3 only): +.no-crypt-add-on +.SH HASHING METHODS +The implemented hashing methods are intended specifically for processing +user passwords for storage and authentication; +they are at best inefficient for most other purposes. +.PP +It is important to understand that password hashing is not a replacement +for strong passwords. +It is always possible for an attacker with access to password hashes +to try guessing candidate passwords against the hashes. +There are, however, certain properties a password hashing method may have +which make these key search attacks somewhat harder. +.PP +All of the hashing methods use salts such that the same +.I key +may produce many possible hashes. +Proper use of salts may defeat a number of attacks, including: +.TP +1. +The ability to try candidate passwords against multiple hashes at the +price of one. +.TP +2. +The use of pre-hashed lists of candidate passwords. +.TP +3. +The ability to determine whether two users (or two accounts of one user) +have the same or different passwords without actually having to guess +one of the passwords. +.PP +The key search attacks depend on computing hashes of large numbers of +candidate passwords. +Thus, the computational cost of a good password hashing method must be +high \- but of course not too high to render it impractical. +.PP +All hashing methods implemented within the +.crypt and +interfaces use multiple iterations of an underlying cryptographic +primitive specifically in order to increase the cost of trying a +candidate password. +Unfortunately, due to hardware improvements, the hashing methods which +have a fixed cost become increasingly less secure over time. +.PP +In addition to salts, modern password hashing methods accept a variable +iteration +.IR count . +This makes it possible to adapt their cost to the hardware improvements +while still maintaining compatibility. +.PP +The following hashing methods are or may be implemented within the +described interfaces: +.PP +.de hash +.ad l +.TP +.I prefix +.ie "\\$1"" \{\ +"" (empty string); +.br +a string matching ^[./0-9A-Za-z]{2} (see +.BR regex (7)) +.\} +.el "\\$1" +.TP +.B Encoding syntax +\\$2 +.TP +.B Maximum password length +\\$3 (uses \\$4-bit characters) +.TP +.B Effective key size +.ie "\\$5"" limited by the hash size only +.el up to \\$5 bits +.TP +.B Hash size +\\$6 bits +.TP +.B Salt size +\\$7 bits +.TP +.B Iteration count +\\$8 +.ad b +.. +.ti -2 +.B Traditional DES-based +.br +This method is supported by almost all implementations of +.BR crypt . +Unfortunately, it no longer offers adequate security because of its many +limitations. +Thus, it should not be used for new passwords unless you absolutely have +to be able to migrate the password hashes to other systems. +.hash "" "[./0-9A-Za-z]{13}" 8 7 56 64 12 25 +.PP +.ti -2 +.B Extended BSDI-style DES-based +.br +This method is used on BSDI and is also available on at least NetBSD, +OpenBSD, and FreeBSD due to the use of David Burren's FreeSec library. +.hash _ "_[./0-9A-Za-z]{19}" unlimited 7 56 64 24 "1 to 2**24-1 (must be odd)" +.PP +.ti -2 +.B FreeBSD-style MD5-based +.br +This is Poul-Henning Kamp's MD5-based password hashing method originally +developed for FreeBSD. +It is currently supported on many free Unix-like systems, on Solaris 10 +and newer, and it is part of the official glibc. +Its main disadvantage is the fixed iteration count, which is already +too low for the currently available hardware. +.hash "$1$" "\e$1\e$[^$]{1,8}\e$[./0-9A-Za-z]{22}" unlimited 8 "" 128 "6 to 48" 1000 +.PP +.ti -2 +.BR "OpenBSD-style Blowfish-based" " (" bcrypt ) +.br +.B bcrypt +was originally developed by Niels Provos and David Mazieres for OpenBSD +and is also supported on recent versions of FreeBSD and NetBSD, +on Solaris 10 and newer, and on several GNU/*/Linux distributions. +It is, however, not part of the official glibc. +.PP +While both +.B bcrypt +and the BSDI-style DES-based hashing offer a variable iteration count, +.B bcrypt +may scale to even faster hardware, doesn't allow for certain optimizations +specific to password cracking only, doesn't have the effective key size +limitation, and uses 8-bit characters in passwords. +.hash "$2b$" "\e$2[abxy]\e$[0-9]{2}\e$[./A-Za-z0-9]{53}" 72 8 "" 184 128 "2**4 to 2**99 (current implementations are limited to 2**31 iterations)" +.PP +With +.BR bcrypt , +the +.I count +passed to +.crypt_gensalt and +is the base-2 logarithm of the actual iteration count. +.PP +.B bcrypt +hashes used the "$2a$" prefix since 1997. +However, in 2011 an implementation bug was discovered in crypt_blowfish +(versions up to 1.0.4 inclusive) affecting handling of password characters with +the 8th bit set. +Besides fixing the bug, +to provide for upgrade strategies for existing systems, two new prefixes were +introduced: "$2x$", which fully re-introduces the bug, and "$2y$", which +guarantees correct handling of both 7- and 8-bit characters. +OpenBSD 5.5 introduced the "$2b$" prefix for behavior that exactly matches +crypt_blowfish's "$2y$", and current crypt_blowfish supports it as well. +Unfortunately, the behavior of "$2a$" on password characters with the 8th bit +set has to be considered system-specific. +When generating new password hashes, the "$2b$" or "$2y$" prefix should be used. +(If such hashes ever need to be migrated to a system that does not yet support +these new prefixes, the prefix in migrated copies of the already-generated +hashes may be changed to "$2a$".) +.PP +.crypt_gensalt and +support the "$2b$", "$2y$", and "$2a$" prefixes (the latter for legacy programs +or configurations), but not "$2x$" (which must not be used for new hashes). +.crypt and +support all four of these prefixes. +.SH PORTABILITY NOTES +Programs using any of these functions on a glibc 2.x system must be +linked against +.BR libcrypt . +However, many Unix-like operating systems and older versions of the +GNU C Library include the +.BR crypt " function in " libc . +.PP +The +.BR crypt_r , +.BR crypt_rn , +.BR crypt_ra , +.crypt_gensalt and +functions are very non-portable. +.PP +The set of supported hashing methods is implementation-dependent. +.SH CONFORMING TO +The +.B crypt +function conforms to SVID, X/OPEN, and is available on BSD 4.3. +The strings returned by +.B crypt +are not required to be portable among conformant systems. +.PP +.B crypt_r +is a GNU extension. +There's also a +.B crypt_r +function on HP-UX and MKS Toolkit, but the prototypes and semantics differ. +.PP +.B crypt_gensalt +is an Openwall extension. +There's also a +.B crypt_gensalt +function on Solaris 10 and newer, but the prototypes and semantics differ. +.PP +.BR crypt_rn , +.BR crypt_ra , +.BR crypt_gensalt_rn , +and +.B crypt_gensalt_ra +are Openwall extensions. +.SH HISTORY +A rotor-based +.B crypt +function appeared in Version 6 AT&T UNIX. +The "traditional" +.B crypt +first appeared in Version 7 AT&T UNIX. +.PP +The +.B crypt_r +function was introduced during glibc 2.0 development. +.SH BUGS +The return values of +.BR crypt " and " crypt_gensalt +point to static buffers that are overwritten by subsequent calls. +These functions are not thread-safe. +.RB ( crypt +on recent versions of Solaris uses thread-specific data and actually is +thread-safe.) +.PP +The strings returned by certain other implementations of +.B crypt +on error may be stored in read-only locations or only initialized once, +which makes it unsafe to always attempt to zero out the buffer normally +pointed to by the +.B crypt +return value as it would otherwise be preferable for security reasons. +The problem could be avoided with the use of +.BR crypt_r , +.BR crypt_rn , +or +.B crypt_ra +where the application has full control over output buffers of these functions +(and often over some of their private data as well). +Unfortunately, the functions aren't (yet?) available on platforms where +.B crypt +has this undesired property. +.PP +Applications using the thread-safe +.B crypt_r +need to allocate address space for the large (over 128 KB) +.I struct crypt_data +structure. Each thread needs a separate instance of the structure. The +.B crypt_r +interface makes it impossible to implement a hashing algorithm which +would need to keep an even larger amount of private data, without breaking +binary compatibility. +.B crypt_ra +allows for dynamically increasing the allocation size as required by the +hashing algorithm that is actually used. Unfortunately, +.B crypt_ra +is even more non-portable than +.BR crypt_r . +.PP +Multi-threaded applications or library functions which are meant to be +thread-safe should use +.BR crypt_gensalt_rn " or " crypt_gensalt_ra +rather than +.BR crypt_gensalt . +.SH SEE ALSO +.BR login (1), +.BR passwd (1), +.BR crypto (3), +.BR encrypt (3), +.BR free (3), +.BR getpass (3), +.BR getpwent (3), +.BR malloc (3), +.BR realloc (3), +.BR shadow (3), +.BR passwd (5), +.BR shadow (5), +.BR regex (7), +.BR pam (8) +.sp +Niels Provos and David Mazieres. A Future-Adaptable Password Scheme. +Proceedings of the 1999 USENIX Annual Technical Conference, June 1999. +.br +http://www.usenix.org/events/usenix99/provos.html +.sp +Robert Morris and Ken Thompson. Password Security: A Case History. +Unix Seventh Edition Manual, Volume 2, April 1978. +.br +http://plan9.bell-labs.com/7thEdMan/vol2/password diff --git a/enet server test/crypt_blowfish/crypt.h b/enet server test/crypt_blowfish/crypt.h new file mode 100644 index 0000000..12e6705 --- /dev/null +++ b/enet server test/crypt_blowfish/crypt.h @@ -0,0 +1,24 @@ +/* + * Written by Solar Designer in 2000-2002. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2002 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#include + +#if defined(_OW_SOURCE) || defined(__USE_OW) +#define __SKIP_GNU +#undef __SKIP_OW +#include +#undef __SKIP_GNU +#endif diff --git a/enet server test/crypt_blowfish/crypt_blowfish.c b/enet server test/crypt_blowfish/crypt_blowfish.c new file mode 100644 index 0000000..9d3f3be --- /dev/null +++ b/enet server test/crypt_blowfish/crypt_blowfish.c @@ -0,0 +1,907 @@ +/* + * The crypt_blowfish homepage is: + * + * http://www.openwall.com/crypt/ + * + * This code comes from John the Ripper password cracker, with reentrant + * and crypt(3) interfaces added, but optimizations specific to password + * cracking removed. + * + * Written by Solar Designer in 1998-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * It is my intent that you should be able to use this on your system, + * as part of a software package, or anywhere else to improve security, + * ensure compatibility, or for any other purpose. I would appreciate + * it if you give credit where it is due and keep your modifications in + * the public domain as well, but I don't require that in order to let + * you place this code and any modifications you make under a license + * of your choice. + * + * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix + * "$2b$", originally by Niels Provos , and it uses + * some of his ideas. The password hashing algorithm was designed by David + * Mazieres . For information on the level of + * compatibility for bcrypt hash prefixes other than "$2b$", please refer to + * the comments in BF_set_key() below and to the included crypt(3) man page. + * + * There's a paper on the algorithm that explains its design decisions: + * + * http://www.usenix.org/events/usenix99/provos.html + * + * Some of the tricks in BF_ROUND might be inspired by Eric Young's + * Blowfish library (I can't be sure if I would think of something if I + * hadn't seen his code). + */ + +#include + +#include +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +/* Just to make sure the prototypes match the actual definitions */ +#include "crypt_blowfish.h" + +#ifdef __i386__ +#define BF_ASM 1 +#define BF_SCALE 1 +#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) +#define BF_ASM 0 +#define BF_SCALE 1 +#else +#define BF_ASM 0 +#define BF_SCALE 0 +#endif + +typedef unsigned int BF_word; +typedef signed int BF_word_signed; + +/* Number of Blowfish rounds, this is also hardcoded into a few places */ +#define BF_N 16 + +typedef BF_word BF_key[BF_N + 2]; + +typedef struct { + BF_word S[4][0x100]; + BF_key P; +} BF_ctx; + +/* + * Magic IV for 64 Blowfish encryptions that we do at the end. + * The string is "OrpheanBeholderScryDoubt" on big-endian. + */ +static BF_word BF_magic_w[6] = { + 0x4F727068, 0x65616E42, 0x65686F6C, + 0x64657253, 0x63727944, 0x6F756274 +}; + +/* + * P-box and S-box tables initialized with digits of Pi. + */ +static BF_ctx BF_init_state = { + { + { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + }, { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + }, { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + }, { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + } + }, { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + } +}; + +static unsigned char BF_itoa64[64 + 1] = + "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static unsigned char BF_atoi64[0x60] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, + 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, + 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 +}; + +#define BF_safe_atoi64(dst, src) \ +{ \ + tmp = (unsigned char)(src); \ + if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ + tmp = BF_atoi64[tmp]; \ + if (tmp > 63) return -1; \ + (dst) = tmp; \ +} + +static int BF_decode(BF_word *dst, const char *src, int size) +{ + unsigned char *dptr = (unsigned char *)dst; + unsigned char *end = dptr + size; + const unsigned char *sptr = (const unsigned char *)src; + unsigned int tmp, c1, c2, c3, c4; + + do { + BF_safe_atoi64(c1, *sptr++); + BF_safe_atoi64(c2, *sptr++); + *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); + if (dptr >= end) break; + + BF_safe_atoi64(c3, *sptr++); + *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); + if (dptr >= end) break; + + BF_safe_atoi64(c4, *sptr++); + *dptr++ = ((c3 & 0x03) << 6) | c4; + } while (dptr < end); + + return 0; +} + +static void BF_encode(char *dst, const BF_word *src, int size) +{ + const unsigned char *sptr = (const unsigned char *)src; + const unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *)dst; + unsigned int c1, c2; + + do { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +static void BF_swap(BF_word *x, int count) +{ + static int endianness_check = 1; + char *is_little_endian = (char *)&endianness_check; + BF_word tmp; + + if (*is_little_endian) + do { + tmp = *x; + tmp = (tmp << 16) | (tmp >> 16); + *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); + } while (--count); +} + +#if BF_SCALE +/* Architectures which can shift addresses left by 2 bits with no extra cost */ +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp2 = L >> 8; \ + tmp2 &= 0xFF; \ + tmp3 = L >> 16; \ + tmp3 &= 0xFF; \ + tmp4 = L >> 24; \ + tmp1 = data.ctx.S[3][tmp1]; \ + tmp2 = data.ctx.S[2][tmp2]; \ + tmp3 = data.ctx.S[1][tmp3]; \ + tmp3 += data.ctx.S[0][tmp4]; \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#else +/* Architectures with no complicated addressing modes supported */ +#define BF_INDEX(S, i) \ + (*((BF_word *)(((unsigned char *)S) + (i)))) +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp1 <<= 2; \ + tmp2 = L >> 6; \ + tmp2 &= 0x3FC; \ + tmp3 = L >> 14; \ + tmp3 &= 0x3FC; \ + tmp4 = L >> 22; \ + tmp4 &= 0x3FC; \ + tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ + tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ + tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ + tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#endif + +/* + * Encrypt one block, BF_N is hardcoded here. + */ +#define BF_ENCRYPT \ + L ^= data.ctx.P[0]; \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + tmp4 = R; \ + R = L; \ + L = tmp4 ^ data.ctx.P[BF_N + 1]; + +#if BF_ASM +#define BF_body() \ + _BF_body_r(&data.ctx); +#else +#define BF_body() \ + L = R = 0; \ + ptr = data.ctx.P; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.P[BF_N + 2]); \ +\ + ptr = data.ctx.S[0]; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.S[3][0xFF]); +#endif + +static void BF_set_key(const char *key, BF_key expanded, BF_key initial, + unsigned char flags) +{ + const char *ptr = key; + unsigned int bug, i, j; + BF_word safety, sign, diff, tmp[2]; + +/* + * There was a sign extension bug in older revisions of this function. While + * we would have liked to simply fix the bug and move on, we have to provide + * a backwards compatibility feature (essentially the bug) for some systems and + * a safety measure for some others. The latter is needed because for certain + * multiple inputs to the buggy algorithm there exist easily found inputs to + * the correct algorithm that produce the same hash. Thus, we optionally + * deviate from the correct algorithm just enough to avoid such collisions. + * While the bug itself affected the majority of passwords containing + * characters with the 8th bit set (although only a percentage of those in a + * collision-producing way), the anti-collision safety measure affects + * only a subset of passwords containing the '\xff' character (not even all of + * those passwords, just some of them). This character is not found in valid + * UTF-8 sequences and is rarely used in popular 8-bit character encodings. + * Thus, the safety measure is unlikely to cause much annoyance, and is a + * reasonable tradeoff to use when authenticating against existing hashes that + * are not reliably known to have been computed with the correct algorithm. + * + * We use an approach that tries to minimize side-channel leaks of password + * information - that is, we mostly use fixed-cost bitwise operations instead + * of branches or table lookups. (One conditional branch based on password + * length remains. It is not part of the bug aftermath, though, and is + * difficult and possibly unreasonable to avoid given the use of C strings by + * the caller, which results in similar timing leaks anyway.) + * + * For actual implementation, we set an array index in the variable "bug" + * (0 means no bug, 1 means sign extension bug emulation) and a flag in the + * variable "safety" (bit 16 is set when the safety measure is requested). + * Valid combinations of settings are: + * + * Prefix "$2a$": bug = 0, safety = 0x10000 + * Prefix "$2b$": bug = 0, safety = 0 + * Prefix "$2x$": bug = 1, safety = 0 + * Prefix "$2y$": bug = 0, safety = 0 + */ + bug = (unsigned int)flags & 1; + safety = ((BF_word)flags & 2) << 15; + + sign = diff = 0; + + for (i = 0; i < BF_N + 2; i++) { + tmp[0] = tmp[1] = 0; + for (j = 0; j < 4; j++) { + tmp[0] <<= 8; + tmp[0] |= (unsigned char)*ptr; /* correct */ + tmp[1] <<= 8; + tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ +/* + * Sign extension in the first char has no effect - nothing to overwrite yet, + * and those extra 24 bits will be fully shifted out of the 32-bit word. For + * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign + * extension in tmp[1] occurs. Once this flag is set, it remains set. + */ + if (j) + sign |= tmp[1] & 0x80; + if (!*ptr) + ptr = key; + else + ptr++; + } + diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ + + expanded[i] = tmp[bug]; + initial[i] = BF_init_state.P[i] ^ tmp[bug]; + } + +/* + * At this point, "diff" is zero iff the correct and buggy algorithms produced + * exactly the same result. If so and if "sign" is non-zero, which indicates + * that there was a non-benign sign extension, this means that we have a + * collision between the correctly computed hash for this password and a set of + * passwords that could be supplied to the buggy algorithm. Our safety measure + * is meant to protect from such many-buggy to one-correct collisions, by + * deviating from the correct algorithm in such cases. Let's check for this. + */ + diff |= diff >> 16; /* still zero iff exact match */ + diff &= 0xffff; /* ditto */ + diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ + sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ + sign &= ~diff & safety; /* action needed? */ + +/* + * If we have determined that we need to deviate from the correct algorithm, + * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but + * let's stick to it now. It came out of the approach we used above, and it's + * not any worse than any other choice we could make.) + * + * It is crucial that we don't do the same to the expanded key used in the main + * Eksblowfish loop. By doing it to only one of these two, we deviate from a + * state that could be directly specified by a password to the buggy algorithm + * (and to the fully correct one as well, but that's a side-effect). + */ + initial[0] ^= sign; +} + +static const unsigned char flags_by_subtype[26] = + {2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; + +static char *BF_crypt(const char *key, const char *setting, + char *output, int size, + BF_word min) +{ +#if BF_ASM + extern void _BF_body_r(BF_ctx *ctx); +#endif + struct { + BF_ctx ctx; + BF_key expanded_key; + union { + BF_word salt[4]; + BF_word output[6]; + } binary; + } data; + BF_word L, R; + BF_word tmp1, tmp2, tmp3, tmp4; + BF_word *ptr; + BF_word count; + int i; + + if (size < 7 + 22 + 31 + 1) { + __set_errno(ERANGE); + return NULL; + } + + if (setting[0] != '$' || + setting[1] != '2' || + setting[2] < 'a' || setting[2] > 'z' || + !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || + setting[3] != '$' || + setting[4] < '0' || setting[4] > '3' || + setting[5] < '0' || setting[5] > '9' || + (setting[4] == '3' && setting[5] > '1') || + setting[6] != '$') { + __set_errno(EINVAL); + return NULL; + } + + count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); + if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { + __set_errno(EINVAL); + return NULL; + } + BF_swap(data.binary.salt, 4); + + BF_set_key(key, data.expanded_key, data.ctx.P, + flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); + + memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); + + L = R = 0; + for (i = 0; i < BF_N + 2; i += 2) { + L ^= data.binary.salt[i & 2]; + R ^= data.binary.salt[(i & 2) + 1]; + BF_ENCRYPT; + data.ctx.P[i] = L; + data.ctx.P[i + 1] = R; + } + + ptr = data.ctx.S[0]; + do { + ptr += 4; + L ^= data.binary.salt[(BF_N + 2) & 3]; + R ^= data.binary.salt[(BF_N + 3) & 3]; + BF_ENCRYPT; + *(ptr - 4) = L; + *(ptr - 3) = R; + + L ^= data.binary.salt[(BF_N + 4) & 3]; + R ^= data.binary.salt[(BF_N + 5) & 3]; + BF_ENCRYPT; + *(ptr - 2) = L; + *(ptr - 1) = R; + } while (ptr < &data.ctx.S[3][0xFF]); + + do { + int done; + + for (i = 0; i < BF_N + 2; i += 2) { + data.ctx.P[i] ^= data.expanded_key[i]; + data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; + } + + done = 0; + do { + BF_body(); + if (done) + break; + done = 1; + + tmp1 = data.binary.salt[0]; + tmp2 = data.binary.salt[1]; + tmp3 = data.binary.salt[2]; + tmp4 = data.binary.salt[3]; + for (i = 0; i < BF_N; i += 4) { + data.ctx.P[i] ^= tmp1; + data.ctx.P[i + 1] ^= tmp2; + data.ctx.P[i + 2] ^= tmp3; + data.ctx.P[i + 3] ^= tmp4; + } + data.ctx.P[16] ^= tmp1; + data.ctx.P[17] ^= tmp2; + } while (1); + } while (--count); + + for (i = 0; i < 6; i += 2) { + L = BF_magic_w[i]; + R = BF_magic_w[i + 1]; + + count = 64; + do { + BF_ENCRYPT; + } while (--count); + + data.binary.output[i] = L; + data.binary.output[i + 1] = R; + } + + memcpy(output, setting, 7 + 22 - 1); + output[7 + 22 - 1] = BF_itoa64[(int) + BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; + +/* This has to be bug-compatible with the original implementation, so + * only encode 23 of the 24 bytes. :-) */ + BF_swap(data.binary.output, 6); + BF_encode(&output[7 + 22], data.binary.output, 23); + output[7 + 22 + 31] = '\0'; + + return output; +} + +int _crypt_output_magic(const char *setting, char *output, int size) +{ + if (size < 3) + return -1; + + output[0] = '*'; + output[1] = '0'; + output[2] = '\0'; + + if (setting[0] == '*' && setting[1] == '0') + output[1] = '1'; + + return 0; +} + +/* + * Please preserve the runtime self-test. It serves two purposes at once: + * + * 1. We really can't afford the risk of producing incompatible hashes e.g. + * when there's something like gcc bug 26587 again, whereas an application or + * library integrating this code might not also integrate our external tests or + * it might not run them after every build. Even if it does, the miscompile + * might only occur on the production build, but not on a testing build (such + * as because of different optimization settings). It is painful to recover + * from incorrectly-computed hashes - merely fixing whatever broke is not + * enough. Thus, a proactive measure like this self-test is needed. + * + * 2. We don't want to leave sensitive data from our actual password hash + * computation on the stack or in registers. Previous revisions of the code + * would do explicit cleanups, but simply running the self-test after hash + * computation is more reliable. + * + * The performance cost of this quick self-test is around 0.6% at the "$2a$08" + * setting. + */ +char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size) +{ + const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; + const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; + static const char * const test_hashes[2] = + {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ + "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ + const char *test_hash = test_hashes[0]; + char *retval; + const char *p; + int save_errno, ok; + struct { + char s[7 + 22 + 1]; + char o[7 + 22 + 31 + 1 + 1 + 1]; + } buf; + +/* Hash the supplied password */ + _crypt_output_magic(setting, output, size); + retval = BF_crypt(key, setting, output, size, 16); + save_errno = errno; + +/* + * Do a quick self-test. It is important that we make both calls to BF_crypt() + * from the same scope such that they likely use the same stack locations, + * which makes the second call overwrite the first call's sensitive data on the + * stack and makes it more likely that any alignment related issues would be + * detected by the self-test. + */ + memcpy(buf.s, test_setting, sizeof(buf.s)); + if (retval) { + unsigned int flags = flags_by_subtype[ + (unsigned int)(unsigned char)setting[2] - 'a']; + test_hash = test_hashes[flags & 1]; + buf.s[2] = setting[2]; + } + memset(buf.o, 0x55, sizeof(buf.o)); + buf.o[sizeof(buf.o) - 1] = 0; + p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); + + ok = (p == buf.o && + !memcmp(p, buf.s, 7 + 22) && + !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1)); + + { + const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; + BF_key ae, ai, ye, yi; + BF_set_key(k, ae, ai, 2); /* $2a$ */ + BF_set_key(k, ye, yi, 4); /* $2y$ */ + ai[0] ^= 0x10000; /* undo the safety (for comparison) */ + ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && + !memcmp(ae, ye, sizeof(ae)) && + !memcmp(ai, yi, sizeof(ai)); + } + + __set_errno(save_errno); + if (ok) + return retval; + +/* Should not happen */ + _crypt_output_magic(setting, output, size); + __set_errno(EINVAL); /* pretend we don't support this hash type */ + return NULL; +} + +char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + if (size < 16 || output_size < 7 + 22 + 1 || + (count && (count < 4 || count > 31)) || + prefix[0] != '$' || prefix[1] != '2' || + (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 5; + + output[0] = '$'; + output[1] = '2'; + output[2] = prefix[2]; + output[3] = '$'; + output[4] = '0' + count / 10; + output[5] = '0' + count % 10; + output[6] = '$'; + + BF_encode(&output[7], (const BF_word *)input, 16); + output[7 + 22] = '\0'; + + return output; +} diff --git a/enet server test/crypt_blowfish/crypt_blowfish.h b/enet server test/crypt_blowfish/crypt_blowfish.h new file mode 100644 index 0000000..2ee0d8c --- /dev/null +++ b/enet server test/crypt_blowfish/crypt_blowfish.h @@ -0,0 +1,27 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_BLOWFISH_H +#define _CRYPT_BLOWFISH_H + +extern int _crypt_output_magic(const char *setting, char *output, int size); +extern char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size); +extern char *_crypt_gensalt_blowfish_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); + +#endif diff --git a/enet server test/crypt_blowfish/crypt_gensalt.c b/enet server test/crypt_blowfish/crypt_gensalt.c new file mode 100644 index 0000000..73c15a1 --- /dev/null +++ b/enet server test/crypt_blowfish/crypt_gensalt.c @@ -0,0 +1,124 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + * + * This file contains salt generation functions for the traditional and + * other common crypt(3) algorithms, except for bcrypt which is defined + * entirely in crypt_blowfish.c. + */ + +#include + +#include +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +/* Just to make sure the prototypes match the actual definitions */ +#include "crypt_gensalt.h" + +unsigned char _crypt_itoa64[64 + 1] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + (void) prefix; + + if (size < 2 || output_size < 2 + 1 || (count && count != 25)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 2 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f]; + output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f]; + output[2] = '\0'; + + return output; +} + +char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + unsigned long value; + + (void) prefix; + +/* Even iteration counts make it easier to detect weak DES keys from a look + * at the hash, so they should be avoided */ + if (size < 3 || output_size < 1 + 4 + 4 + 1 || + (count && (count > 0xffffff || !(count & 1)))) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 725; + + output[0] = '_'; + output[1] = _crypt_itoa64[count & 0x3f]; + output[2] = _crypt_itoa64[(count >> 6) & 0x3f]; + output[3] = _crypt_itoa64[(count >> 12) & 0x3f]; + output[4] = _crypt_itoa64[(count >> 18) & 0x3f]; + value = (unsigned long)(unsigned char)input[0] | + ((unsigned long)(unsigned char)input[1] << 8) | + ((unsigned long)(unsigned char)input[2] << 16); + output[5] = _crypt_itoa64[value & 0x3f]; + output[6] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[7] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[8] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[9] = '\0'; + + return output; +} + +char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + unsigned long value; + + (void) prefix; + + if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL); + return NULL; + } + + output[0] = '$'; + output[1] = '1'; + output[2] = '$'; + value = (unsigned long)(unsigned char)input[0] | + ((unsigned long)(unsigned char)input[1] << 8) | + ((unsigned long)(unsigned char)input[2] << 16); + output[3] = _crypt_itoa64[value & 0x3f]; + output[4] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[5] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[6] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[7] = '\0'; + + if (size >= 6 && output_size >= 3 + 4 + 4 + 1) { + value = (unsigned long)(unsigned char)input[3] | + ((unsigned long)(unsigned char)input[4] << 8) | + ((unsigned long)(unsigned char)input[5] << 16); + output[7] = _crypt_itoa64[value & 0x3f]; + output[8] = _crypt_itoa64[(value >> 6) & 0x3f]; + output[9] = _crypt_itoa64[(value >> 12) & 0x3f]; + output[10] = _crypt_itoa64[(value >> 18) & 0x3f]; + output[11] = '\0'; + } + + return output; +} diff --git a/enet server test/crypt_blowfish/crypt_gensalt.h b/enet server test/crypt_blowfish/crypt_gensalt.h new file mode 100644 index 0000000..457bbfe --- /dev/null +++ b/enet server test/crypt_blowfish/crypt_gensalt.h @@ -0,0 +1,30 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_GENSALT_H +#define _CRYPT_GENSALT_H + +extern unsigned char _crypt_itoa64[]; +extern char *_crypt_gensalt_traditional_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); +extern char *_crypt_gensalt_extended_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); +extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size); + +#endif diff --git a/enet server test/crypt_blowfish/glibc-2.1.3-crypt.diff b/enet server test/crypt_blowfish/glibc-2.1.3-crypt.diff new file mode 100644 index 0000000..415e5b4 --- /dev/null +++ b/enet server test/crypt_blowfish/glibc-2.1.3-crypt.diff @@ -0,0 +1,53 @@ +--- glibc-2.1.3.orig/crypt/sysdeps/unix/Makefile 1997-03-05 00:33:59 +0000 ++++ glibc-2.1.3/crypt/sysdeps/unix/Makefile 2000-06-11 03:13:41 +0000 +@@ -1,4 +1,4 @@ + ifeq ($(subdir),md5-crypt) +-libcrypt-routines += crypt crypt_util +-dont_distribute += crypt.c crypt_util.c ++libcrypt-routines += crypt crypt_util crypt_blowfish x86 crypt_gensalt wrapper ++dont_distribute += crypt.c crypt_util.c crypt_blowfish.c x86.S crypt_gensalt.c wrapper.c + endif +--- glibc-2.1.3.orig/crypt/sysdeps/unix/crypt-entry.c 1998-12-10 12:49:04 +0000 ++++ glibc-2.1.3/crypt/sysdeps/unix/crypt-entry.c 2000-06-11 03:14:57 +0000 +@@ -70,7 +70,7 @@ extern struct crypt_data _ufc_foobar; + */ + + char * +-__crypt_r (key, salt, data) ++__des_crypt_r (key, salt, data) + const char *key; + const char *salt; + struct crypt_data * __restrict data; +@@ -115,6 +115,7 @@ __crypt_r (key, salt, data) + _ufc_output_conversion_r (res[0], res[1], salt, data); + return data->crypt_3_buf; + } ++#if 0 + weak_alias (__crypt_r, crypt_r) + + char * +@@ -147,3 +148,4 @@ __fcrypt (key, salt) + return crypt (key, salt); + } + #endif ++#endif +--- glibc-2.1.3.orig/md5-crypt/Makefile 1998-07-02 22:46:47 +0000 ++++ glibc-2.1.3/md5-crypt/Makefile 2000-06-11 03:12:34 +0000 +@@ -21,7 +21,7 @@ + # + subdir := md5-crypt + +-headers := crypt.h ++headers := crypt.h gnu-crypt.h ow-crypt.h + + distribute := md5.h + +--- glibc-2.1.3.orig/md5-crypt/Versions 1998-07-02 22:32:07 +0000 ++++ glibc-2.1.3/md5-crypt/Versions 2000-06-11 09:11:03 +0000 +@@ -1,5 +1,6 @@ + libcrypt { + GLIBC_2.0 { + crypt; crypt_r; encrypt; encrypt_r; fcrypt; setkey; setkey_r; ++ crypt_rn; crypt_ra; crypt_gensalt; crypt_gensalt_rn; crypt_gensalt_ra; + } + } diff --git a/enet server test/crypt_blowfish/glibc-2.14-crypt.diff b/enet server test/crypt_blowfish/glibc-2.14-crypt.diff new file mode 100644 index 0000000..bacd12e --- /dev/null +++ b/enet server test/crypt_blowfish/glibc-2.14-crypt.diff @@ -0,0 +1,55 @@ +diff -urp glibc-2.14.orig/crypt/Makefile glibc-2.14/crypt/Makefile +--- glibc-2.14.orig/crypt/Makefile 2011-05-31 04:12:33 +0000 ++++ glibc-2.14/crypt/Makefile 2011-07-16 21:40:56 +0000 +@@ -22,6 +22,7 @@ + subdir := crypt + + headers := crypt.h ++headers += gnu-crypt.h ow-crypt.h + + extra-libs := libcrypt + extra-libs-others := $(extra-libs) +@@ -29,6 +30,8 @@ extra-libs-others := $(extra-libs) + libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt crypt \ + crypt_util + ++libcrypt-routines += crypt_blowfish x86 crypt_gensalt wrapper ++ + tests := cert md5c-test sha256c-test sha512c-test + + distribute := ufc-crypt.h crypt-private.h ufc.c speeds.c README.ufc-crypt \ +diff -urp glibc-2.14.orig/crypt/Versions glibc-2.14/crypt/Versions +--- glibc-2.14.orig/crypt/Versions 2011-05-31 04:12:33 +0000 ++++ glibc-2.14/crypt/Versions 2011-07-16 21:40:56 +0000 +@@ -1,5 +1,6 @@ + libcrypt { + GLIBC_2.0 { + crypt; crypt_r; encrypt; encrypt_r; fcrypt; setkey; setkey_r; ++ crypt_rn; crypt_ra; crypt_gensalt; crypt_gensalt_rn; crypt_gensalt_ra; + } + } +diff -urp glibc-2.14.orig/crypt/crypt-entry.c glibc-2.14/crypt/crypt-entry.c +--- glibc-2.14.orig/crypt/crypt-entry.c 2011-05-31 04:12:33 +0000 ++++ glibc-2.14/crypt/crypt-entry.c 2011-07-16 21:40:56 +0000 +@@ -82,7 +82,7 @@ extern struct crypt_data _ufc_foobar; + */ + + char * +-__crypt_r (key, salt, data) ++__des_crypt_r (key, salt, data) + const char *key; + const char *salt; + struct crypt_data * __restrict data; +@@ -137,6 +137,7 @@ __crypt_r (key, salt, data) + _ufc_output_conversion_r (res[0], res[1], salt, data); + return data->crypt_3_buf; + } ++#if 0 + weak_alias (__crypt_r, crypt_r) + + char * +@@ -177,3 +178,4 @@ __fcrypt (key, salt) + return crypt (key, salt); + } + #endif ++#endif diff --git a/enet server test/crypt_blowfish/glibc-2.3.6-crypt.diff b/enet server test/crypt_blowfish/glibc-2.3.6-crypt.diff new file mode 100644 index 0000000..4471054 --- /dev/null +++ b/enet server test/crypt_blowfish/glibc-2.3.6-crypt.diff @@ -0,0 +1,52 @@ +--- glibc-2.3.6.orig/crypt/Makefile 2001-07-06 04:54:45 +0000 ++++ glibc-2.3.6/crypt/Makefile 2004-02-27 00:23:48 +0000 +@@ -21,14 +21,14 @@ + # + subdir := crypt + +-headers := crypt.h ++headers := crypt.h gnu-crypt.h ow-crypt.h + + distribute := md5.h + + extra-libs := libcrypt + extra-libs-others := $(extra-libs) + +-libcrypt-routines := crypt-entry md5-crypt md5 crypt crypt_util ++libcrypt-routines := crypt-entry md5-crypt md5 crypt crypt_util crypt_blowfish x86 crypt_gensalt wrapper + + tests = cert md5test md5c-test + +--- glibc-2.3.6.orig/crypt/Versions 2000-03-04 00:47:30 +0000 ++++ glibc-2.3.6/crypt/Versions 2004-02-27 00:25:15 +0000 +@@ -1,5 +1,6 @@ + libcrypt { + GLIBC_2.0 { + crypt; crypt_r; encrypt; encrypt_r; fcrypt; setkey; setkey_r; ++ crypt_rn; crypt_ra; crypt_gensalt; crypt_gensalt_rn; crypt_gensalt_ra; + } + } +--- glibc-2.3.6.orig/crypt/crypt-entry.c 2001-07-06 05:18:49 +0000 ++++ glibc-2.3.6/crypt/crypt-entry.c 2004-02-27 00:12:32 +0000 +@@ -70,7 +70,7 @@ extern struct crypt_data _ufc_foobar; + */ + + char * +-__crypt_r (key, salt, data) ++__des_crypt_r (key, salt, data) + const char *key; + const char *salt; + struct crypt_data * __restrict data; +@@ -115,6 +115,7 @@ __crypt_r (key, salt, data) + _ufc_output_conversion_r (res[0], res[1], salt, data); + return data->crypt_3_buf; + } ++#if 0 + weak_alias (__crypt_r, crypt_r) + + char * +@@ -147,3 +148,4 @@ __fcrypt (key, salt) + return crypt (key, salt); + } + #endif ++#endif diff --git a/enet server test/crypt_blowfish/ow-crypt.h b/enet server test/crypt_blowfish/ow-crypt.h new file mode 100644 index 0000000..2e48794 --- /dev/null +++ b/enet server test/crypt_blowfish/ow-crypt.h @@ -0,0 +1,43 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _OW_CRYPT_H +#define _OW_CRYPT_H + +#ifndef __GNUC__ +#undef __const +#define __const const +#endif + +#ifndef __SKIP_GNU +extern char *crypt(__const char *key, __const char *setting); +extern char *crypt_r(__const char *key, __const char *setting, void *data); +#endif + +#ifndef __SKIP_OW +extern char *crypt_rn(__const char *key, __const char *setting, + void *data, int size); +extern char *crypt_ra(__const char *key, __const char *setting, + void **data, int *size); +extern char *crypt_gensalt(__const char *prefix, unsigned long count, + __const char *input, int size); +extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count, + __const char *input, int size, char *output, int output_size); +extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count, + __const char *input, int size); +#endif + +#endif diff --git a/enet server test/crypt_blowfish/wrapper.c b/enet server test/crypt_blowfish/wrapper.c new file mode 100644 index 0000000..d8b0592 --- /dev/null +++ b/enet server test/crypt_blowfish/wrapper.c @@ -0,0 +1,551 @@ +/* + * Written by Solar Designer in 2000-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#include +#include + +#include +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +#ifdef TEST +#include +#include +#include +#include +#include +#include +#ifdef TEST_THREADS +#include +#endif +#endif + +#define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1) +#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1) + +#if defined(__GLIBC__) && defined(_LIBC) +#define __SKIP_GNU +#endif +#include "ow-crypt.h" + +#include "crypt_blowfish.h" +#include "crypt_gensalt.h" + +#if defined(__GLIBC__) && defined(_LIBC) +/* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */ +#include "crypt.h" +extern char *__md5_crypt_r(const char *key, const char *salt, + char *buffer, int buflen); +/* crypt-entry.c needs to be patched to define __des_crypt_r rather than + * __crypt_r, and not define crypt_r and crypt at all */ +extern char *__des_crypt_r(const char *key, const char *salt, + struct crypt_data *data); +extern struct crypt_data _ufc_foobar; +#endif + +static int _crypt_data_alloc(void **data, int *size, int need) +{ + void *updated; + + if (*data && *size >= need) return 0; + + updated = realloc(*data, need); + + if (!updated) { +#ifndef __GLIBC__ + /* realloc(3) on glibc sets errno, so we don't need to bother */ + __set_errno(ENOMEM); +#endif + return -1; + } + +#if defined(__GLIBC__) && defined(_LIBC) + if (need >= sizeof(struct crypt_data)) + ((struct crypt_data *)updated)->initialized = 0; +#endif + + *data = updated; + *size = need; + + return 0; +} + +static char *_crypt_retval_magic(char *retval, const char *setting, + char *output, int size) +{ + if (retval) + return retval; + + if (_crypt_output_magic(setting, output, size)) + return NULL; /* shouldn't happen */ + + return output; +} + +#if defined(__GLIBC__) && defined(_LIBC) +/* + * Applications may re-use the same instance of struct crypt_data without + * resetting the initialized field in order to let crypt_r() skip some of + * its initialization code. Thus, it is important that our multiple hashing + * algorithms either don't conflict with each other in their use of the + * data area or reset the initialized field themselves whenever required. + * Currently, the hashing algorithms simply have no conflicts: the first + * field of struct crypt_data is the 128-byte large DES key schedule which + * __des_crypt_r() calculates each time it is called while the two other + * hashing algorithms use less than 128 bytes of the data area. + */ + +char *__crypt_rn(__const char *key, __const char *setting, + void *data, int size) +{ + if (setting[0] == '$' && setting[1] == '2') + return _crypt_blowfish_rn(key, setting, (char *)data, size); + if (setting[0] == '$' && setting[1] == '1') + return __md5_crypt_r(key, setting, (char *)data, size); + if (setting[0] == '$' || setting[0] == '_') { + __set_errno(EINVAL); + return NULL; + } + if (size >= sizeof(struct crypt_data)) + return __des_crypt_r(key, setting, (struct crypt_data *)data); + __set_errno(ERANGE); + return NULL; +} + +char *__crypt_ra(__const char *key, __const char *setting, + void **data, int *size) +{ + if (setting[0] == '$' && setting[1] == '2') { + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return _crypt_blowfish_rn(key, setting, (char *)*data, *size); + } + if (setting[0] == '$' && setting[1] == '1') { + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return __md5_crypt_r(key, setting, (char *)*data, *size); + } + if (setting[0] == '$' || setting[0] == '_') { + __set_errno(EINVAL); + return NULL; + } + if (_crypt_data_alloc(data, size, sizeof(struct crypt_data))) + return NULL; + return __des_crypt_r(key, setting, (struct crypt_data *)*data); +} + +char *__crypt_r(__const char *key, __const char *setting, + struct crypt_data *data) +{ + return _crypt_retval_magic( + __crypt_rn(key, setting, data, sizeof(*data)), + setting, (char *)data, sizeof(*data)); +} + +char *__crypt(__const char *key, __const char *setting) +{ + return _crypt_retval_magic( + __crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)), + setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar)); +} +#else +char *crypt_rn(const char *key, const char *setting, void *data, int size) +{ + return _crypt_blowfish_rn(key, setting, (char *)data, size); +} + +char *crypt_ra(const char *key, const char *setting, + void **data, int *size) +{ + if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) + return NULL; + return _crypt_blowfish_rn(key, setting, (char *)*data, *size); +} + +char *crypt_r(const char *key, const char *setting, void *data) +{ + return _crypt_retval_magic( + crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE), + setting, (char *)data, CRYPT_OUTPUT_SIZE); +} + +char *crypt(const char *key, const char *setting) +{ + static char output[CRYPT_OUTPUT_SIZE]; + + return _crypt_retval_magic( + crypt_rn(key, setting, output, sizeof(output)), + setting, output, sizeof(output)); +} + +#define __crypt_gensalt_rn crypt_gensalt_rn +#define __crypt_gensalt_ra crypt_gensalt_ra +#define __crypt_gensalt crypt_gensalt +#endif + +char *__crypt_gensalt_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + char *(*use)(const char *_prefix, unsigned long _count, + const char *_input, int _size, + char *_output, int _output_size); + + /* This may be supported on some platforms in the future */ + if (!input) { + __set_errno(EINVAL); + return NULL; + } + + if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) || + !strncmp(prefix, "$2y$", 4)) + use = _crypt_gensalt_blowfish_rn; + else + if (!strncmp(prefix, "$1$", 3)) + use = _crypt_gensalt_md5_rn; + else + if (prefix[0] == '_') + use = _crypt_gensalt_extended_rn; + else + if (!prefix[0] || + (prefix[0] && prefix[1] && + memchr(_crypt_itoa64, prefix[0], 64) && + memchr(_crypt_itoa64, prefix[1], 64))) + use = _crypt_gensalt_traditional_rn; + else { + __set_errno(EINVAL); + return NULL; + } + + return use(prefix, count, input, size, output, output_size); +} + +char *__crypt_gensalt_ra(const char *prefix, unsigned long count, + const char *input, int size) +{ + char output[CRYPT_GENSALT_OUTPUT_SIZE]; + char *retval; + + retval = __crypt_gensalt_rn(prefix, count, + input, size, output, sizeof(output)); + + if (retval) { + retval = _strdup(retval); +#ifndef __GLIBC__ + /* strdup(3) on glibc sets errno, so we don't need to bother */ + if (!retval) + __set_errno(ENOMEM); +#endif + } + + return retval; +} + +char *__crypt_gensalt(const char *prefix, unsigned long count, + const char *input, int size) +{ + static char output[CRYPT_GENSALT_OUTPUT_SIZE]; + + return __crypt_gensalt_rn(prefix, count, + input, size, output, sizeof(output)); +} + +#if defined(__GLIBC__) && defined(_LIBC) +weak_alias(__crypt_rn, crypt_rn) +weak_alias(__crypt_ra, crypt_ra) +weak_alias(__crypt_r, crypt_r) +weak_alias(__crypt, crypt) +weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn) +weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra) +weak_alias(__crypt_gensalt, crypt_gensalt) +weak_alias(crypt, fcrypt) +#endif + +#ifdef TEST +static const char *tests[][3] = { + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", + "U*U"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", + "U*U*"}, + {"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", + "U*U*U"}, + {"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui", + "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "chars after 72 are ignored"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xa3"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.", + "\xff\xff\xa3"}, + {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", + "\xff\xff\xa3"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", + "\xa3"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "1\xa3" "345"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "345"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.", + "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", + "\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", + "\xff\xa3" "345"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", + "\xa3" "ab"}, + {"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS", + "\xd1\x91"}, + {"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS", + "\xd0\xc1\xd2\xcf\xcc\xd8"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "chars after 72 are ignored as usual"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy", + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" + "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"}, + {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe", + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" + "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", + ""}, + {"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."}, + {"*1", "", "*0"}, + {NULL} +}; + +#define which tests[0] + +static volatile sig_atomic_t running; + +static void handle_timer(int signum) +{ + (void) signum; + running = 0; +} + +static void *run(void *arg) +{ + unsigned long count = 0; + int i = 0; + void *data = NULL; + int size = 0x12345678; + + do { + const char *hash = tests[i][0]; + const char *key = tests[i][1]; + const char *setting = tests[i][2]; + + if (!tests[++i][0]) + i = 0; + + if (setting && strlen(hash) < 30) /* not for benchmark */ + continue; + + if (strcmp(crypt_ra(key, hash, &data, &size), hash)) { + printf("%d: FAILED (crypt_ra/%d/%lu)\n", + (int)((char *)arg - (char *)0), i, count); + free(data); + return NULL; + } + count++; + } while (running); + + free(data); + return count + (char *)0; +} + +int main(void) +{ + struct itimerval it; + struct tms buf; + clock_t clk_tck, start_real, start_virtual, end_real, end_virtual; + unsigned long count; + void *data; + int size; + char *setting1, *setting2; + int i; +#ifdef TEST_THREADS + pthread_t t[TEST_THREADS]; + void *t_retval; +#endif + + data = NULL; + size = 0x12345678; + + for (i = 0; tests[i][0]; i++) { + const char *hash = tests[i][0]; + const char *key = tests[i][1]; + const char *setting = tests[i][2]; + const char *p; + int ok = !setting || strlen(hash) >= 30; + int o_size; + char s_buf[30], o_buf[61]; + if (!setting) { + memcpy(s_buf, hash, sizeof(s_buf) - 1); + s_buf[sizeof(s_buf) - 1] = 0; + setting = s_buf; + } + + __set_errno(0); + p = crypt(key, setting); + if ((!ok && !errno) || strcmp(p, hash)) { + printf("FAILED (crypt/%d)\n", i); + return 1; + } + + if (ok && strcmp(crypt(key, hash), hash)) { + printf("FAILED (crypt/%d)\n", i); + return 1; + } + + for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) { + int ok_n = ok && o_size == (int)sizeof(o_buf); + const char *x = "abc"; + strcpy(o_buf, x); + if (o_size >= 3) { + x = "*0"; + if (setting[0] == '*' && setting[1] == '0') + x = "*1"; + } + __set_errno(0); + p = crypt_rn(key, setting, o_buf, o_size); + if ((ok_n && (!p || strcmp(p, hash))) || + (!ok_n && (!errno || p || strcmp(o_buf, x)))) { + printf("FAILED (crypt_rn/%d)\n", i); + return 1; + } + } + + __set_errno(0); + p = crypt_ra(key, setting, &data, &size); + if ((ok && (!p || strcmp(p, hash))) || + (!ok && (!errno || p || strcmp((char *)data, hash)))) { + printf("FAILED (crypt_ra/%d)\n", i); + return 1; + } + } + + setting1 = crypt_gensalt(which[0], 12, data, size); + if (!setting1 || strncmp(setting1, "$2a$12$", 7)) { + puts("FAILED (crypt_gensalt)\n"); + return 1; + } + + setting2 = crypt_gensalt_ra(setting1, 12, data, size); + if (strcmp(setting1, setting2)) { + puts("FAILED (crypt_gensalt_ra/1)\n"); + return 1; + } + + (*(char *)data)++; + setting1 = crypt_gensalt_ra(setting2, 12, data, size); + if (!strcmp(setting1, setting2)) { + puts("FAILED (crypt_gensalt_ra/2)\n"); + return 1; + } + + free(setting1); + free(setting2); + free(data); + +#if defined(_SC_CLK_TCK) || !defined(CLK_TCK) + clk_tck = sysconf(_SC_CLK_TCK); +#else + clk_tck = CLK_TCK; +#endif + + running = 1; + signal(SIGALRM, handle_timer); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 5; + setitimer(ITIMER_REAL, &it, NULL); + + start_real = times(&buf); + start_virtual = buf.tms_utime + buf.tms_stime; + + count = (char *)run((char *)0) - (char *)0; + + end_real = times(&buf); + end_virtual = buf.tms_utime + buf.tms_stime; + if (end_virtual == start_virtual) end_virtual++; + + printf("%.1f c/s real, %.1f c/s virtual\n", + (float)count * clk_tck / (end_real - start_real), + (float)count * clk_tck / (end_virtual - start_virtual)); + +#ifdef TEST_THREADS + running = 1; + it.it_value.tv_sec = 60; + setitimer(ITIMER_REAL, &it, NULL); + start_real = times(&buf); + + for (i = 0; i < TEST_THREADS; i++) + if (pthread_create(&t[i], NULL, run, i + (char *)0)) { + perror("pthread_create"); + return 1; + } + + for (i = 0; i < TEST_THREADS; i++) { + if (pthread_join(t[i], &t_retval)) { + perror("pthread_join"); + continue; + } + if (!t_retval) continue; + count = (char *)t_retval - (char *)0; + end_real = times(&buf); + printf("%d: %.1f c/s real\n", i, + (float)count * clk_tck / (end_real - start_real)); + } +#endif + + return 0; +} +#endif diff --git a/enet server test/crypt_blowfish/x86.S b/enet server test/crypt_blowfish/x86.S new file mode 100644 index 0000000..b0f1cd2 --- /dev/null +++ b/enet server test/crypt_blowfish/x86.S @@ -0,0 +1,203 @@ +/* + * Written by Solar Designer in 1998-2010. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2010 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifdef __i386__ + +#if defined(__OpenBSD__) && !defined(__ELF__) +#define UNDERSCORES +#define ALIGN_LOG +#endif + +#if defined(__CYGWIN32__) || defined(__MINGW32__) +#define UNDERSCORES +#endif + +#ifdef __DJGPP__ +#define UNDERSCORES +#define ALIGN_LOG +#endif + +#ifdef UNDERSCORES +#define _BF_body_r __BF_body_r +#endif + +#ifdef ALIGN_LOG +#define DO_ALIGN(log) .align (log) +#elif defined(DUMBAS) +#define DO_ALIGN(log) .align 1 << log +#else +#define DO_ALIGN(log) .align (1 << (log)) +#endif + +#define BF_FRAME 0x200 +#define ctx %esp + +#define BF_ptr (ctx) + +#define S(N, r) N+BF_FRAME(ctx,r,4) +#ifdef DUMBAS +#define P(N) 0x1000+N+N+N+N+BF_FRAME(ctx) +#else +#define P(N) 0x1000+4*N+BF_FRAME(ctx) +#endif + +/* + * This version of the assembly code is optimized primarily for the original + * Intel Pentium but is also careful to avoid partial register stalls on the + * Pentium Pro family of processors (tested up to Pentium III Coppermine). + * + * It is possible to do 15% faster on the Pentium Pro family and probably on + * many non-Intel x86 processors, but, unfortunately, that would make things + * twice slower for the original Pentium. + * + * An additional 2% speedup may be achieved with non-reentrant code. + */ + +#define L %esi +#define R %edi +#define tmp1 %eax +#define tmp1_lo %al +#define tmp2 %ecx +#define tmp2_hi %ch +#define tmp3 %edx +#define tmp3_lo %dl +#define tmp4 %ebx +#define tmp4_hi %bh +#define tmp5 %ebp + +.text + +#define BF_ROUND(L, R, N) \ + xorl L,tmp2; \ + xorl tmp1,tmp1; \ + movl tmp2,L; \ + shrl $16,tmp2; \ + movl L,tmp4; \ + movb tmp2_hi,tmp1_lo; \ + andl $0xFF,tmp2; \ + movb tmp4_hi,tmp3_lo; \ + andl $0xFF,tmp4; \ + movl S(0,tmp1),tmp1; \ + movl S(0x400,tmp2),tmp5; \ + addl tmp5,tmp1; \ + movl S(0x800,tmp3),tmp5; \ + xorl tmp5,tmp1; \ + movl S(0xC00,tmp4),tmp5; \ + addl tmp1,tmp5; \ + movl 4+P(N),tmp2; \ + xorl tmp5,R + +#define BF_ENCRYPT_START \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + movl BF_ptr,tmp5; \ + xorl L,tmp2; \ + movl P(17),L + +#define BF_ENCRYPT_END \ + xorl R,L; \ + movl tmp2,R + +DO_ALIGN(5) +.globl _BF_body_r +_BF_body_r: + movl 4(%esp),%eax + pushl %ebp + pushl %ebx + pushl %esi + pushl %edi + subl $BF_FRAME-8,%eax + xorl L,L + cmpl %esp,%eax + ja BF_die + xchgl %eax,%esp + xorl R,R + pushl %eax + leal 0x1000+BF_FRAME-4(ctx),%eax + movl 0x1000+BF_FRAME-4(ctx),tmp2 + pushl %eax + xorl tmp3,tmp3 +BF_loop_P: + BF_ENCRYPT_START + addl $8,tmp5 + BF_ENCRYPT_END + leal 0x1000+18*4+BF_FRAME(ctx),tmp1 + movl tmp5,BF_ptr + cmpl tmp5,tmp1 + movl L,-8(tmp5) + movl R,-4(tmp5) + movl P(0),tmp2 + ja BF_loop_P + leal BF_FRAME(ctx),tmp5 + xorl tmp3,tmp3 + movl tmp5,BF_ptr +BF_loop_S: + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,(tmp5) + movl R,4(tmp5) + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,8(tmp5) + movl R,12(tmp5) + BF_ENCRYPT_START + BF_ENCRYPT_END + movl P(0),tmp2 + movl L,16(tmp5) + movl R,20(tmp5) + BF_ENCRYPT_START + addl $32,tmp5 + BF_ENCRYPT_END + leal 0x1000+BF_FRAME(ctx),tmp1 + movl tmp5,BF_ptr + cmpl tmp5,tmp1 + movl P(0),tmp2 + movl L,-8(tmp5) + movl R,-4(tmp5) + ja BF_loop_S + movl 4(%esp),%esp + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + +BF_die: +/* Oops, need to re-compile with a larger BF_FRAME. */ + hlt + jmp BF_die + +#endif + +#if defined(__ELF__) && defined(__linux__) +.section .note.GNU-stack,"",@progbits +#endif diff --git a/enet server test/enet server test.cpp b/enet server test/enet server test.cpp new file mode 100644 index 0000000..9f5e325 --- /dev/null +++ b/enet server test/enet server test.cpp @@ -0,0 +1,3322 @@ +/********************************************************************************** + First Growtopia Private Server made with ENet. + Copyright (C) 2018 Growtopia Noobs + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +**********************************************************************************/ + + +#include "stdafx.h" +#include + +#include "enet/enet.h" +#include +#include +#include +#include +#include +#include +#include "json.hpp" +#include "bcrypt.h" +#include "crypt_blowfish/crypt_gensalt.c" +#include "crypt_blowfish/crypt_blowfish.h" +#include "crypt_blowfish/crypt_blowfish.c" +#include "crypt_blowfish/wrapper.c" +#include "bcrypt.c" +#include +#include // TODO +#include // TODO + +using namespace std; +using json = nlohmann::json; + +//#define TOTAL_LOG +#define REGISTRATION + +ENetHost * server; +int cId = 1; +BYTE* itemsDat = 0; +int itemsDatSize = 0; + +/***bcrypt***/ + +bool verifyPassword(string password, string hash) { + int ret; + + ret = bcrypt_checkpw(password.c_str(), hash.c_str()); + assert(ret != -1); + + return !ret; +} + +string hashPassword(string password) { + char salt[BCRYPT_HASHSIZE]; + char hash[BCRYPT_HASHSIZE]; + int ret; + + ret = bcrypt_gensalt(12, salt); + assert(ret == 0); + ret = bcrypt_hashpw(password.c_str(), salt, hash); + assert(ret == 0); + return hash; +} + +/***bcrypt**/ + +void sendData(ENetPeer* peer, int num, char* data, int len) +{ + /* Create a reliable packet of size 7 containing "packet\0" */ + ENetPacket * packet = enet_packet_create(0, + len + 5, + ENET_PACKET_FLAG_RELIABLE); + /* Extend the packet so and append the string "foo", so it now */ + /* contains "packetfoo\0" */ + /* Send the packet to the peer over channel id 0. */ + /* One could also broadcast the packet by */ + /* enet_host_broadcast (host, 0, packet); */ + memcpy(packet->data, &num, 4); + if (data != NULL) + { + memcpy(packet->data+4, data, len); + } + char zero = 0; + memcpy(packet->data + 4 + len, &zero, 1); + enet_peer_send(peer, 0, packet); + enet_host_flush(server); +} + +int getPacketId(char* data) +{ + return *data; +} + +char* getPacketData(char* data) +{ + return data + 4; +} + +string text_encode(char* text) +{ + string ret = ""; + while (text[0] != 0) + { + switch (text[0]) + { + case '\n': + ret += "\\n"; + break; + case '\t': + ret += "\\t"; + break; + case '\b': + ret += "\\b"; + break; + case '\\': + ret += "\\\\"; + break; + case '\r': + ret += "\\r"; + break; + default: + ret += text[0]; + break; + } + text++; + } + return ret; +} + +int ch2n(char x) +{ + switch (x) + { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'A': + return 10; + case 'B': + return 11; + case 'C': + return 12; + case 'D': + return 13; + case 'E': + return 14; + case 'F': + return 15; + default: + break; + } +} + + +char* GetTextPointerFromPacket(ENetPacket* packet) +{ + char zero = 0; + memcpy(packet->data + packet->dataLength - 1, &zero, 1); + return (char*)(packet->data + 4); +} + +BYTE* GetStructPointerFromTankPacket(ENetPacket* packet) +{ + unsigned int packetLenght = packet->dataLength; + BYTE* result = NULL; + if (packetLenght >= 0x3C) + { + BYTE* packetData = packet->data; + result = packetData + 4; + if (*(BYTE*)(packetData + 16) & 8) + { + if (packetLenght < *(int*)(packetData + 56) + 60) + { + cout << "Packet too small for extended packet to be valid" << endl; + cout << "Sizeof float is 4. TankUpdatePacket size: 56" << endl; + result = 0; + } + } + else + { + int zero = 0; + memcpy(packetData + 56, &zero, 4); + } + } + return result; +} + +int GetMessageTypeFromPacket(ENetPacket* packet) +{ + int result; + + if (packet->dataLength > 3u) + { + result = *(packet->data); + } + else + { + cout << "Bad packet length, ignoring message" << endl; + result = 0; + } + return result; +} + + +vector explode(const string &delimiter, const string &str) +{ + vector arr; + + int strleng = str.length(); + int delleng = delimiter.length(); + if (delleng == 0) + return arr;//no change + + int i = 0; + int k = 0; + while (i 61 * 2) throw 0; + } + GamePacket packet; + packet.data = data; + packet.len = 61; + packet.indexes = 0; + return packet; +} + +GamePacket packetEnd(GamePacket p) +{ + BYTE* n = new BYTE[p.len + 1]; + memcpy(n, p.data, p.len); + delete p.data; + p.data = n; + char zero = 0; + memcpy(p.data+p.len, &zero, 1); + p.len += 1; + //*(int*)(p.data + 52) = p.len; + *(int*)(p.data + 56) = p.indexes;//p.len-60;//p.indexes; + *(BYTE*)(p.data + 60) = p.indexes; + //*(p.data + 57) = p.indexes; + return p; +} + +struct InventoryItem { + __int16 itemID; + __int8 itemCount; +}; + +struct PlayerInventory { + vector items; + int inventorySize = 100; +}; + +#define cloth0 cloth_hair +#define cloth1 cloth_shirt +#define cloth2 cloth_pants +#define cloth3 cloth_feet +#define cloth4 cloth_face +#define cloth5 cloth_hand +#define cloth6 cloth_back +#define cloth7 cloth_mask +#define cloth8 cloth_necklace + +struct PlayerInfo { + bool isIn = false; + int netID; + bool haveGrowId = false; + string tankIDName = ""; + string tankIDPass = ""; + string requestedName = ""; + string rawName = ""; + string displayName = ""; + string country = ""; + int adminLevel = 0; + string currentWorld = "EXIT"; + bool radio = true; + int x; + int y; + bool isRotatedLeft = false; + + bool isUpdating = false; + bool joinClothesUpdated = false; + + int cloth_hair = 0; // 0 + int cloth_shirt = 0; // 1 + int cloth_pants = 0; // 2 + int cloth_feet = 0; // 3 + int cloth_face = 0; // 4 + int cloth_hand = 0; // 5 + int cloth_back = 0; // 6 + int cloth_mask = 0; // 7 + int cloth_necklace = 0; // 8 + + bool canWalkInBlocks = false; // 1 + bool canDoubleJump = false; // 2 + bool isInvisible = false; // 4 + bool noHands = false; // 8 + bool noEyes = false; // 16 + bool noBody = false; // 32 + bool devilHorns = false; // 64 + bool goldenHalo = false; // 128 + bool isFrozen = false; // 2048 + bool isCursed = false; // 4096 + bool isDuctaped = false; // 8192 + bool haveCigar = false; // 16384 + bool isShining = false; // 32768 + bool isZombie = false; // 65536 + bool isHitByLava = false; // 131072 + bool haveHauntedShadows = false; // 262144 + bool haveGeigerRadiation = false; // 524288 + bool haveReflector = false; // 1048576 + bool isEgged = false; // 2097152 + bool havePineappleFloag = false; // 4194304 + bool haveFlyingPineapple = false; // 8388608 + bool haveSuperSupporterName = false; // 16777216 + bool haveSupperPineapple = false; // 33554432 + //bool + int skinColor = 0x268DAFFF; + + PlayerInventory inventory; + + long long int lastSB = 0; +}; + + +int getState(PlayerInfo* info) { + int val = 0; + val |= info->canWalkInBlocks << 0; + val |= info->canDoubleJump << 1; + val |= info->isInvisible << 2; + val |= info->noHands << 3; + val |= info->noEyes << 4; + val |= info->noBody << 5; + val |= info->devilHorns << 6; + val |= info->goldenHalo << 7; + return val; +} + + +struct WorldItem { + __int16 foreground = 0; + __int16 background = 0; + int breakLevel = 0; + long long int breakTime = 0; + bool water = false; + bool fire = false; + bool glue = false; + bool red = false; + bool green = false; + bool blue = false; + +}; + +struct WorldInfo { + int width = 100; + int height = 60; + string name = "TEST"; + WorldItem* items; + string owner = ""; + bool isPublic=false; +}; + +WorldInfo generateWorld(string name, int width, int height) +{ + WorldInfo world; + world.name = name; + world.width = width; + world.height = height; + world.items = new WorldItem[world.width*world.height]; + for (int i = 0; i < world.width*world.height; i++) + { + if (i >= 3800 && i<5400 && !(rand() % 50)) + world.items[i].foreground = 10; + else if (i >= 3700 && i<5400) + { + world.items[i].foreground = 2; + } + else if (i >= 5400) { + world.items[i].foreground = 8; + } + if (i >= 3700) + world.items[i].background = 14; + if (i == 3650) + world.items[i].foreground = 6; + else if (i >= 3600 && i<3700) + world.items[i].foreground = 16; + if (i == 3750) + world.items[i].foreground = 8; + } + return world; +} + + +class PlayerDB { +public: + static string getProperName(string name); + static string PlayerDB::fixColors(string text); + static int playerLogin(ENetPeer* peer, string username, string password); + static int playerRegister(string username, string password); +}; + +string PlayerDB::getProperName(string name) { + string newS; + for (char c : name) newS+=(c >= 'A' && c <= 'Z') ? c-('A'-'a') : c; + string ret; + for (int i = 0; i < newS.length(); i++) + { + if (newS[i] == '`') i++; else ret += newS[i]; + } + string ret2; + for (char c : ret) if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) ret2 += c; + return ret2; +} + +string PlayerDB::fixColors(string text) { + string ret = ""; + int colorLevel = 0; + for (int i = 0; i < text.length(); i++) + { + if (text[i] == '`') + { + ret += text[i]; + if (i + 1 < text.length()) + ret += text[i + 1]; + + + if (i+1 < text.length() && text[i + 1] == '`') + { + colorLevel--; + } + else { + colorLevel++; + } + i++; + } else { + ret += text[i]; + } + } + for (int i = 0; i < colorLevel; i++) { + ret += "``"; + } + for (int i = 0; i > colorLevel; i--) { + ret += "`w"; + } + return ret; +} + +int PlayerDB::playerLogin(ENetPeer* peer, string username, string password) { + std::ifstream ifs("players/" + PlayerDB::getProperName(username) + ".json"); + if (ifs.is_open()) { + json j; + ifs >> j; + string pss = j["password"]; + if (verifyPassword(password, pss)) { + ENetPeer * currentPeer; + + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (currentPeer == peer) + continue; + if (((PlayerInfo*)(currentPeer->data))->rawName == PlayerDB::getProperName(username)) + { + { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Someone else logged to this account!")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet); + delete p.data; + } + { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Someone else was logged to this account! He was kicked out now.")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + } + //enet_host_flush(server); + enet_peer_disconnect_later(currentPeer, 0); + } + } + return 1; + } + else { + return -1; + } + } + else { + return -2; + } +} + +int PlayerDB::playerRegister(string username, string password) { + username = PlayerDB::getProperName(username); + if (username.length() < 3) return -2; + std::ifstream ifs("players/" + username + ".json"); + if (ifs.is_open()) { + return -1; + } + + std::ofstream o("players/" + username + ".json"); + if (!o.is_open()) { + cout << GetLastError() << endl; + _getch(); + } + json j; + j["username"] = username; + j["password"] = hashPassword(password); + j["adminLevel"] = 0; + o << j << std::endl; + return 1; +} + +struct AWorld { + WorldInfo* ptr; + WorldInfo info; + int id; +}; + +class WorldDB { +public: + WorldInfo get(string name); + AWorld get2(string name); + void flush(WorldInfo info); + void flush2(AWorld info); + void save(AWorld info); + void saveAll(); + void saveRedundant(); + vector getRandomWorlds(); + WorldDB(); +private: + vector worlds; +}; + +WorldDB::WorldDB() { + // Constructor +} + +string getStrUpper(string txt) { + string ret; + for (char c : txt) ret += toupper(c); + return ret; +} + +AWorld WorldDB::get2(string name) { + if (worlds.size() > 200) { +#ifdef TOTAL_LOG + cout << "Saving redundant worlds!" << endl; +#endif + saveRedundant(); +#ifdef TOTAL_LOG + cout << "Redundant worlds are saved!" << endl; +#endif + } + AWorld ret; + name = getStrUpper(name); + if (name.length() < 1) throw 1; // too short name + for (char c : name) { + if ((c<'A' || c>'Z') && (c<'0' || c>'9')) + throw 2; // wrong name + } + if (name == "EXIT") { + throw 3; + } + for (int i = 0; i < worlds.size(); i++) { + if (worlds.at(i).name == name) + { + ret.id = i; + ret.info = worlds.at(i); + ret.ptr = &worlds.at(i); + return ret; + } + + } + std::ifstream ifs("worlds/" + name + ".json"); + if (ifs.is_open()) { + + json j; + ifs >> j; + WorldInfo info; + info.name = j["name"]; + info.width = j["width"]; + info.height = j["height"]; + info.owner = j["owner"]; + info.isPublic = j["isPublic"]; + json tiles = j["tiles"]; + int square = info.width*info.height; + info.items = new WorldItem[square]; + for (int i = 0; i < square; i++) { + info.items[i].foreground = tiles[i]["fg"]; + info.items[i].background = tiles[i]["bg"]; + } + worlds.push_back(info); + ret.id = worlds.size() - 1; + ret.info = info; + ret.ptr = &worlds.at(worlds.size() - 1); + return ret; + } + else { + WorldInfo info = generateWorld(name, 100, 60); + + worlds.push_back(info); + ret.id = worlds.size() - 1; + ret.info = info; + ret.ptr = &worlds.at(worlds.size() - 1); + return ret; + } + throw 1; +} + +WorldInfo WorldDB::get(string name) { + + return this->get2(name).info; +} + +void WorldDB::flush(WorldInfo info) +{ + std::ofstream o("worlds/" + info.name + ".json"); + if (!o.is_open()) { + cout << GetLastError() << endl; + } + json j; + j["name"] = info.name; + j["width"] = info.width; + j["height"] = info.height; + j["owner"] = info.owner; + j["isPublic"] = info.isPublic; + json tiles = json::array(); + int square = info.width*info.height; + + for (int i = 0; i < square; i++) + { + json tile; + tile["fg"] = info.items[i].foreground; + tile["bg"] = info.items[i].background; + tiles.push_back(tile); + } + j["tiles"] = tiles; + o << j << std::endl; +} + +void WorldDB::flush2(AWorld info) +{ + this->flush(info.info); +} + +void WorldDB::save(AWorld info) +{ + flush2(info); + delete info.info.items; + worlds.erase(worlds.begin() + info.id); +} + +void WorldDB::saveAll() +{ + for (int i = 0; i < worlds.size(); i++) { + flush(worlds.at(i)); + delete worlds.at(i).items; + } + worlds.clear(); +} + +vector WorldDB::getRandomWorlds() { + vector ret; + for (int i = 0; i < ((worlds.size() < 10) ? worlds.size() : 10); i++) + { // load first four worlds, it is excepted that they are special + ret.push_back(worlds.at(i)); + } + // and lets get up to 6 random + if (worlds.size() > 4) { + for (int j = 0; j < 6; j++) + { + bool isPossible = true; + WorldInfo world = worlds.at(rand() % (worlds.size() - 4)); + for (int i = 0; i < ret.size(); i++) + { + if (world.name == ret.at(i).name || world.name == "EXIT") + { + isPossible = false; + } + } + if (isPossible) + ret.push_back(world); + } + } + return ret; +} + +void WorldDB::saveRedundant() +{ + for (int i = 4; i < worlds.size(); i++) { + bool canBeFree = true; + ENetPeer * currentPeer; + + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (((PlayerInfo*)(currentPeer->data))->currentWorld == worlds.at(i).name) + canBeFree = false; + } + if (canBeFree) + { + flush(worlds.at(i)); + delete worlds.at(i).items; + worlds.erase(worlds.begin() + i); + i--; + } + } +} + +//WorldInfo world; +//vector worlds; +WorldDB worldDB; + +void saveAllWorlds() // atexit hack plz fix +{ + cout << "Saving worlds..." << endl; + worldDB.saveAll(); + cout << "Worlds saved!" << endl; +} + +WorldInfo* getPlyersWorld(ENetPeer* peer) +{ + try { + return worldDB.get2(((PlayerInfo*)(peer->data))->currentWorld).ptr; + } catch(int e) { + return NULL; + } +} + +struct PlayerMoving { + int packetType; + int netID; + float x; + float y; + int characterState; + int plantingTree; + float XSpeed; + float YSpeed; + int punchX; + int punchY; + +}; + + +enum ClothTypes { + HAIR, + SHIRT, + PANTS, + FEET, + FACE, + HAND, + BACK, + MASK, + NECKLACE, + NONE +}; + +enum BlockTypes { + FOREGROUND, + BACKGROUND, + SEED, + PAIN_BLOCK, + BEDROCK, + MAIN_DOOR, + SIGN, + DOOR, + CLOTHING, + FIST, + UNKNOWN +}; + +struct ItemDefinition { + int id; + string name; + int rarity; + int breakHits; + int growTime; + ClothTypes clothType; + BlockTypes blockType; + string description = "This item has no description."; +}; + +vector itemDefs; + +struct DroppedItem { // TODO + int id; + int uid; + int count; +}; + +vector droppedItems; + +ItemDefinition getItemDef(int id) +{ + if (id < itemDefs.size() && id > -1) + return itemDefs.at(id); + /*for (int i = 0; i < itemDefs.size(); i++) + { + if (id == itemDefs.at(i).id) + { + return itemDefs.at(i); + } + }*/ + throw 0; + return itemDefs.at(0); +} + +void craftItemDescriptions() { + int current = -1; + std::ifstream infile("Descriptions.txt"); + for (std::string line; getline(infile, line);) + { + if (line.length() > 3 && line[0] != '/' && line[1] != '/') + { + vector ex = explode("|", line); + ItemDefinition def; + if (atoi(ex[0].c_str()) + 1 < itemDefs.size()) + { + itemDefs.at(atoi(ex[0].c_str())).description = ex[1]; + if (!(atoi(ex[0].c_str()) % 2)) + itemDefs.at(atoi(ex[0].c_str()) + 1).description = "This is tree."; + } + } + } +} + +void buildItemsDatabase() +{ + int current = -1; + std::ifstream infile("CoreData.txt"); + for (std::string line; getline(infile, line);) + { + if (line.length() > 8 && line[0] != '/' && line[1] != '/') + { + vector ex = explode("|", line); + ItemDefinition def; + def.id = atoi(ex[0].c_str()); + def.name = ex[1]; + def.rarity = atoi(ex[2].c_str()); + string bt = ex[4]; + if (bt == "Foreground_Block") { + def.blockType = BlockTypes::FOREGROUND; + } + else if(bt == "Seed") { + def.blockType = BlockTypes::SEED; + } + else if (bt == "Pain_Block") { + def.blockType = BlockTypes::PAIN_BLOCK; + } + else if (bt == "Main_Door") { + def.blockType = BlockTypes::MAIN_DOOR; + } + else if (bt == "Bedrock") { + def.blockType = BlockTypes::BEDROCK; + } + else if (bt == "Door") { + def.blockType = BlockTypes::DOOR; + } + else if (bt == "Fist") { + def.blockType = BlockTypes::FIST; + } + else if (bt == "Sign") { + def.blockType = BlockTypes::SIGN; + } + else if (bt == "Background_Block") { + def.blockType = BlockTypes::BACKGROUND; + } + else { + def.blockType = BlockTypes::UNKNOWN; + } + def.breakHits = atoi(ex[7].c_str()); + def.growTime = atoi(ex[8].c_str()); + string cl = ex[9]; + if (cl == "None") { + def.clothType = ClothTypes::NONE; + } + else if(cl == "Hat") { + def.clothType = ClothTypes::HAIR; + } + else if(cl == "Shirt") { + def.clothType = ClothTypes::SHIRT; + } + else if(cl == "Pants") { + def.clothType = ClothTypes::PANTS; + } + else if (cl == "Feet") { + def.clothType = ClothTypes::FEET; + } + else if (cl == "Face") { + def.clothType = ClothTypes::FACE; + } + else if (cl == "Hand") { + def.clothType = ClothTypes::HAND; + } + else if (cl == "Back") { + def.clothType = ClothTypes::BACK; + } + else if (cl == "Hair") { + def.clothType = ClothTypes::MASK; + } + else if (cl == "Chest") { + def.clothType = ClothTypes::NECKLACE; + } + else { + def.clothType = ClothTypes::NONE; + } + + if (++current != def.id) + { + cout << "Critical error! Unordered database at item "<< std::to_string(current) <<"/"<< std::to_string(def.id) <<"!" << endl; + } + + itemDefs.push_back(def); + } + } + craftItemDescriptions(); +} + +struct Admin { + string username; + string password; + int level = 0; + long long int lastSB = 0; +}; + +vector admins; + +void addAdmin(string username, string password, int level) +{ + Admin admin; + admin.username = username; + admin.password = password; + admin.level = level; + admins.push_back(admin); +} + +int getAdminLevel(string username, string password) { + for (int i = 0; i < admins.size(); i++) { + Admin admin = admins[i]; + if (admin.username == username && admin.password == password) { + return admin.level; + } + } + return 0; +} + +bool canSB(string username, string password) { + for (int i = 0; i < admins.size(); i++) { + Admin admin = admins[i]; + if (admin.username == username && admin.password == password && admin.level>1) { + using namespace std::chrono; + if (admin.lastSB + 900000 < (duration_cast(system_clock::now().time_since_epoch())).count() || admin.level == 999) + { + admins[i].lastSB = (duration_cast(system_clock::now().time_since_epoch())).count(); + return true; + } + else { + return false; + } + } + } + return false; +} + +bool canClear(string username, string password) { + for (int i = 0; i < admins.size(); i++) { + Admin admin = admins[i]; + if (admin.username == username && admin.password == password) { + return admin.level > 0; + } + } + return false; +} + +bool isSuperAdmin(string username, string password) { + for (int i = 0; i < admins.size(); i++) { + Admin admin = admins[i]; + if (admin.username == username && admin.password == password && admin.level == 999) { + return true; + } + } + return false; +} + +bool isHere(ENetPeer* peer, ENetPeer* peer2) +{ + return ((PlayerInfo*)(peer->data))->currentWorld == ((PlayerInfo*)(peer2->data))->currentWorld; +} + +void sendInventory(ENetPeer* peer, PlayerInventory inventory) +{ + string asdf2 = "0400000009A7379237BB2509E8E0EC04F8720B050000000000000000FBBB0000010000007D920100FDFDFDFD04000000040000000000000000000000000000000000"; + int inventoryLen = inventory.items.size(); + int packetLen = (asdf2.length() / 2) + (inventoryLen * 4) + 4; + BYTE* data2 = new BYTE[packetLen]; + for (int i = 0; i < asdf2.length(); i += 2) + { + char x = ch2n(asdf2[i]); + x = x << 4; + x += ch2n(asdf2[i + 1]); + memcpy(data2 + (i / 2), &x, 1); + } + int endianInvVal = _byteswap_ulong(inventoryLen); + memcpy(data2 + (asdf2.length() / 2) - 4, &endianInvVal, 4); + endianInvVal = _byteswap_ulong(inventory.inventorySize); + memcpy(data2 + (asdf2.length() / 2) - 8, &endianInvVal, 4); + int val = 0; + for (int i = 0; i < inventoryLen; i++) + { + val = 0; + val |= inventory.items.at(i).itemID; + val |= inventory.items.at(i).itemCount << 16; + val &= 0x00FFFFFF; + val |= 0x00 << 24; + memcpy(data2 + (i*4) + (asdf2.length() / 2), &val, 4); + } + ENetPacket * packet3 = enet_packet_create(data2, + packetLen, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet3); + delete data2; + //enet_host_flush(server); +} + +BYTE* packPlayerMoving(PlayerMoving* dataStruct) +{ + BYTE* data = new BYTE[56]; + for (int i = 0; i < 56; i++) + { + data[i] = 0; + } + memcpy(data, &dataStruct->packetType, 4); + memcpy(data + 4, &dataStruct->netID, 4); + memcpy(data + 12, &dataStruct->characterState, 4); + memcpy(data + 20, &dataStruct->plantingTree, 4); + memcpy(data + 24, &dataStruct->x, 4); + memcpy(data + 28, &dataStruct->y, 4); + memcpy(data + 32, &dataStruct->XSpeed, 4); + memcpy(data + 36, &dataStruct->YSpeed, 4); + memcpy(data + 44, &dataStruct->punchX, 4); + memcpy(data + 48, &dataStruct->punchY, 4); + return data; +} + +PlayerMoving* unpackPlayerMoving(BYTE* data) +{ + PlayerMoving* dataStruct = new PlayerMoving; + memcpy(&dataStruct->packetType, data, 4); + memcpy(&dataStruct->netID, data + 4, 4); + memcpy(&dataStruct->characterState, data + 12, 4); + memcpy(&dataStruct->plantingTree, data + 20, 4); + memcpy(&dataStruct->x, data + 24, 4); + memcpy(&dataStruct->y, data + 28, 4); + memcpy(&dataStruct->XSpeed, data + 32, 4); + memcpy(&dataStruct->YSpeed, data + 36, 4); + memcpy(&dataStruct->punchX, data + 44, 4); + memcpy(&dataStruct->punchY, data + 48, 4); + return dataStruct; +} + +void SendPacket(int a1, string a2, ENetPeer* enetPeer) +{ + if (enetPeer) + { + ENetPacket* v3 = enet_packet_create(0, a2.length() + 5, 1); + memcpy(v3->data, &a1, 4); + //*(v3->data) = (DWORD)a1; + memcpy((v3->data) + 4, a2.c_str(), a2.length()); + + //cout << std::hex << (int)(char)v3->data[3] << endl; + enet_peer_send(enetPeer, 0, v3); + } +} + +void SendPacketRaw(int a1, void *packetData, size_t packetDataSize, void *a4, ENetPeer* peer, int packetFlag) +{ + ENetPacket *p; + + if (peer) // check if we have it setup + { + if (a1 == 4 && *((BYTE *)packetData + 12) & 8) + { + p = enet_packet_create(0, packetDataSize + *((DWORD *)packetData + 13) + 5, packetFlag); + int four = 4; + memcpy(p->data, &four, 4); + memcpy((char *)p->data + 4, packetData, packetDataSize); + memcpy((char *)p->data + packetDataSize + 4, a4, *((DWORD *)packetData + 13)); + enet_peer_send(peer, 0, p); + } + else + { + p = enet_packet_create(0, packetDataSize + 5, packetFlag); + memcpy(p->data, &a1, 4); + memcpy((char *)p->data + 4, packetData, packetDataSize); + enet_peer_send(peer, 0, p); + } + } + delete packetData; +} + + + void onPeerConnect(ENetPeer* peer) + { + ENetPeer * currentPeer; + + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (peer != currentPeer) + { + if (isHere(peer, currentPeer)) + { + string netIdS = std::to_string(((PlayerInfo*)(currentPeer->data))->netID); + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnSpawn"), "spawn|avatar\nnetID|" + netIdS + "\nuserID|" + netIdS + "\ncolrect|0|0|20|30\nposXY|" + std::to_string(((PlayerInfo*)(currentPeer->data))->x) + "|" + std::to_string(((PlayerInfo*)(currentPeer->data))->y) + "\nname|``" + ((PlayerInfo*)(currentPeer->data))->displayName + "``\ncountry|" + ((PlayerInfo*)(currentPeer->data))->country + "\ninvis|0\nmstate|0\nsmstate|0\n")); // ((PlayerInfo*)(server->peers[i].data))->tankIDName + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(peer, 0, packet); + delete p.data; + string netIdS2 = std::to_string(((PlayerInfo*)(peer->data))->netID); + GamePacket p2 = packetEnd(appendString(appendString(createPacket(), "OnSpawn"), "spawn|avatar\nnetID|" + netIdS2 + "\nuserID|" + netIdS2 + "\ncolrect|0|0|20|30\nposXY|" + std::to_string(((PlayerInfo*)(peer->data))->x) + "|" + std::to_string(((PlayerInfo*)(peer->data))->y) + "\nname|``" + ((PlayerInfo*)(peer->data))->displayName + "``\ncountry|" + ((PlayerInfo*)(peer->data))->country + "\ninvis|0\nmstate|0\nsmstate|0\n")); // ((PlayerInfo*)(server->peers[i].data))->tankIDName + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet2); + delete p2.data; + //enet_host_flush(server); + } + } + } + + } + + void updateAllClothes(ENetPeer* peer) + { + ENetPeer * currentPeer; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) + { + GamePacket p3 = packetEnd(appendFloat(appendIntx(appendFloat(appendFloat(appendFloat(appendString(createPacket(), "OnSetClothing"), ((PlayerInfo*)(peer->data))->cloth_hair, ((PlayerInfo*)(peer->data))->cloth_shirt, ((PlayerInfo*)(peer->data))->cloth_pants), ((PlayerInfo*)(peer->data))->cloth_feet, ((PlayerInfo*)(peer->data))->cloth_face, ((PlayerInfo*)(peer->data))->cloth_hand), ((PlayerInfo*)(peer->data))->cloth_back, ((PlayerInfo*)(peer->data))->cloth_mask, ((PlayerInfo*)(peer->data))->cloth_necklace), ((PlayerInfo*)(peer->data))->skinColor), 0.0f, 0.0f, 0.0f)); + memcpy(p3.data + 8, &(((PlayerInfo*)(peer->data))->netID), 4); // ffloor + ENetPacket * packet3 = enet_packet_create(p3.data, + p3.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(currentPeer, 0, packet3); + delete p3.data; + //enet_host_flush(server); + GamePacket p4 = packetEnd(appendFloat(appendIntx(appendFloat(appendFloat(appendFloat(appendString(createPacket(), "OnSetClothing"), ((PlayerInfo*)(currentPeer->data))->cloth_hair, ((PlayerInfo*)(currentPeer->data))->cloth_shirt, ((PlayerInfo*)(currentPeer->data))->cloth_pants), ((PlayerInfo*)(currentPeer->data))->cloth_feet, ((PlayerInfo*)(currentPeer->data))->cloth_face, ((PlayerInfo*)(currentPeer->data))->cloth_hand), ((PlayerInfo*)(currentPeer->data))->cloth_back, ((PlayerInfo*)(currentPeer->data))->cloth_mask, ((PlayerInfo*)(currentPeer->data))->cloth_necklace), ((PlayerInfo*)(currentPeer->data))->skinColor), 0.0f, 0.0f, 0.0f)); + memcpy(p4.data + 8, &(((PlayerInfo*)(currentPeer->data))->netID), 4); // ffloor + ENetPacket * packet4 = enet_packet_create(p4.data, + p4.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet4); + delete p4.data; + //enet_host_flush(server); + } + } + } + + void sendClothes(ENetPeer* peer) + { + ENetPeer * currentPeer; + GamePacket p3 = packetEnd(appendFloat(appendIntx(appendFloat(appendFloat(appendFloat(appendString(createPacket(), "OnSetClothing"), ((PlayerInfo*)(peer->data))->cloth_hair, ((PlayerInfo*)(peer->data))->cloth_shirt, ((PlayerInfo*)(peer->data))->cloth_pants), ((PlayerInfo*)(peer->data))->cloth_feet, ((PlayerInfo*)(peer->data))->cloth_face, ((PlayerInfo*)(peer->data))->cloth_hand), ((PlayerInfo*)(peer->data))->cloth_back, ((PlayerInfo*)(peer->data))->cloth_mask, ((PlayerInfo*)(peer->data))->cloth_necklace), ((PlayerInfo*)(peer->data))->skinColor), 0.0f, 0.0f, 0.0f)); + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) + { + + memcpy(p3.data + 8, &(((PlayerInfo*)(peer->data))->netID), 4); // ffloor + ENetPacket * packet3 = enet_packet_create(p3.data, + p3.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(currentPeer, 0, packet3); + } + + } + //enet_host_flush(server); + delete p3.data; + } + + void sendPData(ENetPeer* peer, PlayerMoving* data) + { + ENetPeer * currentPeer; + + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (peer != currentPeer) + { + if (isHere(peer, currentPeer)) + { + data->netID = ((PlayerInfo*)(peer->data))->netID; + + SendPacketRaw(4, packPlayerMoving(data), 56, 0, currentPeer, ENET_PACKET_FLAG_RELIABLE); + } + } + } + } + + int getPlayersCountInWorld(string name) + { + int count = 0; + ENetPeer * currentPeer; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (((PlayerInfo*)(currentPeer->data))->currentWorld == name) + count++; + } + return count; + } + + void sendRoulete(ENetPeer* peer, int x, int y) + { + ENetPeer* currentPeer; + int val = rand() % 37; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) + { + GamePacket p2 = packetEnd(appendIntx(appendString(appendIntx(appendString(createPacket(), "OnTalkBubble"), ((PlayerInfo*)(peer->data))->netID), "Your number is "+std::to_string(val)+"."), 0)); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet2); + delete p2.data; + } + + + //cout << "Tile update at: " << data2->punchX << "x" << data2->punchY << endl; + } + } + + void sendNothingHappened(ENetPeer* peer, int x, int y) { + PlayerMoving data; + data.netID = ((PlayerInfo*)(peer->data))->netID; + data.packetType = 0x8; + data.plantingTree = 0; + data.netID = -1; + data.x = x; + data.y = y; + data.punchX = x; + data.punchY = y; + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE); + } + + void sendTileUpdate(int x, int y, int tile, int causedBy, ENetPeer* peer) + { + PlayerMoving data; + //data.packetType = 0x14; + data.packetType = 0x3; + + //data.characterState = 0x924; // animation + data.characterState = 0x0; // animation + data.x = x; + data.y = y; + data.punchX = x; + data.punchY = y; + data.XSpeed = 0; + data.YSpeed = 0; + data.netID = causedBy; + data.plantingTree = tile; + + WorldInfo *world = getPlyersWorld(peer); + + if (world == NULL) return; + if (x<0 || y<0 || x>world->width || y>world->height) return; + sendNothingHappened(peer,x,y); + if (!isSuperAdmin(((PlayerInfo*)(peer->data))->rawName, ((PlayerInfo*)(peer->data))->tankIDPass)) + { + if (world->items[x + (y*world->width)].foreground == 6 || world->items[x + (y*world->width)].foreground == 8 || world->items[x + (y*world->width)].foreground == 3760) + return; + if (tile == 6 || tile == 8 || tile == 3760) + return; + } + if (world->name == "ADMIN" && !getAdminLevel(((PlayerInfo*)(peer->data))->rawName, ((PlayerInfo*)(peer->data))->tankIDPass)) + { + if (world->items[x + (y*world->width)].foreground == 758) + sendRoulete(peer, x, y); + return; + } + if (world->name != "ADMIN") { + if (world->owner != "") { + if (((PlayerInfo*)(peer->data))->rawName == world->owner) { + // WE ARE GOOD TO GO + if (tile == 32) { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnDialogRequest"), "set_default_color|`o\n\nadd_label_with_icon|big|`wShould this world be publicly breakable?``|left|242|\n\nadd_spacer|small|\nadd_button_with_icon|worldPublic|Public|noflags|2408||\nadd_button_with_icon|worldPrivate|Private|noflags|202||\nadd_spacer|small|\nadd_quick_exit|\nadd_button|chc0|Close|noflags|0|0|\nnend_dialog|gazette||OK|")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + //enet_host_flush(server); + delete p.data; + } + } + else if (world->isPublic) + { + if (world->items[x + (y*world->width)].foreground == 242) + { + return; + } + } + else { + return; + } + if (tile == 242) { + return; + } + } + } + if (tile == 32) { + // TODO + return; + } + if (tile == 822) { + world->items[x + (y*world->width)].water = !world->items[x + (y*world->width)].water; + return; + } + if (tile == 3062) + { + world->items[x + (y*world->width)].fire = !world->items[x + (y*world->width)].fire; + return; + } + if (tile == 1866) + { + world->items[x + (y*world->width)].glue = !world->items[x + (y*world->width)].glue; + return; + } + ItemDefinition def; + try { + def = getItemDef(tile); + if (def.clothType != ClothTypes::NONE) return; + } + catch (int e) { + def.breakHits = 4; + def.blockType = BlockTypes::UNKNOWN; +#ifdef TOTAL_LOG + cout << "Ugh, unsupported item " << tile << endl; +#endif + } + + if (tile == 544 || tile == 546 || tile == 4520 || tile == 382 || tile == 3116 || tile == 4520 || tile == 1792 || tile == 5666 || tile==2994 || tile==4368) return; + if (tile == 5708 || tile == 5709 || tile == 5780 || tile == 5781 || tile == 5782 || tile == 5783 || tile == 5784 || tile == 5785 || tile == 5710 || tile == 5711 || tile == 5786 || tile == 5787 || tile == 5788 || tile == 5789 || tile == 5790 || tile == 5791 || tile == 6146 || tile == 6147 || tile == 6148 || tile == 6149 || tile == 6150 || tile == 6151 || tile == 6152 || tile == 6153 || tile == 5670 || tile == 5671 || tile == 5798 || tile == 5799 || tile == 5800 || tile == 5801 || tile == 5802 || tile == 5803 || tile == 5668 || tile == 5669 || tile == 5792 || tile == 5793 || tile == 5794 || tile == 5795 || tile == 5796 || tile == 5797 || tile == 544 || tile == 546 || tile == 4520 || tile == 382 || tile == 3116 || tile == 1792 || tile == 5666 || tile == 2994 || tile == 4368) return; + if(tile == 1902 || tile == 1508 || tile == 428) return; + if (tile == 410 || tile == 1770 || tile == 4720 || tile == 4882 || tile == 6392 || tile == 3212 || tile == 1832 || tile == 4742 || tile == 3496 || tile == 3270 || tile == 4722) return; + if (tile >= 7068) return; + if (tile == 0 || tile == 18) { + //data.netID = -1; + data.packetType = 0x8; + data.plantingTree = 4; + using namespace std::chrono; + //if (world->items[x + (y*world->width)].foreground == 0) return; + if ((duration_cast(system_clock::now().time_since_epoch())).count() - world->items[x + (y*world->width)].breakTime >= 4000) + { + world->items[x + (y*world->width)].breakTime = (duration_cast(system_clock::now().time_since_epoch())).count(); + world->items[x + (y*world->width)].breakLevel = 4; // TODO + if (world->items[x + (y*world->width)].foreground == 758) + sendRoulete(peer, x, y); + } + else + if (y < world->height && world->items[x + (y*world->width)].breakLevel + 4 >= def.breakHits * 4) { // TODO + data.packetType = 0x3;// 0xC; // 0xF // World::HandlePacketTileChangeRequest + data.netID = -1; + data.plantingTree = 0; + world->items[x + (y*world->width)].breakLevel = 0; + if (world->items[x + (y*world->width)].foreground != 0) + { + if (world->items[x + (y*world->width)].foreground == 242) + { + world->owner = ""; + world->isPublic = false; + } + world->items[x + (y*world->width)].foreground = 0; + } + else { + world->items[x + (y*world->width)].background = 0; + } + + } + else + if (y < world->height) + { + world->items[x + (y*world->width)].breakTime = (duration_cast(system_clock::now().time_since_epoch())).count(); + world->items[x + (y*world->width)].breakLevel += 4; // TODO + if (world->items[x + (y*world->width)].foreground == 758) + sendRoulete(peer, x, y); + } + + } + else { + for (int i = 0; i < ((PlayerInfo*)(peer->data))->inventory.items.size(); i++) + { + if (((PlayerInfo*)(peer->data))->inventory.items.at(i).itemID == tile) + { + if ((unsigned int)((PlayerInfo*)(peer->data))->inventory.items.at(i).itemCount>1) + { + ((PlayerInfo*)(peer->data))->inventory.items.at(i).itemCount--; + } + else { + ((PlayerInfo*)(peer->data))->inventory.items.erase(((PlayerInfo*)(peer->data))->inventory.items.begin() + i); + + } + } + } + if (def.blockType == BlockTypes::BACKGROUND) + { + world->items[x + (y*world->width)].background = tile; + } + else { + world->items[x + (y*world->width)].foreground = tile; + if (tile == 242) { + world->owner = ((PlayerInfo*)(peer->data))->rawName; + world->isPublic = false; + } + } + + world->items[x + (y*world->width)].breakLevel = 0; + } + + ENetPeer * currentPeer; + + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, currentPeer, ENET_PACKET_FLAG_RELIABLE); + + //cout << "Tile update at: " << data2->punchX << "x" << data2->punchY << endl; + } + } + + void sendPlayerLeave(ENetPeer* peer, PlayerInfo* player) + { + ENetPeer * currentPeer; + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnRemove"), "netID|" + std::to_string(player->netID) + "\n")); // ((PlayerInfo*)(server->peers[i].data))->tankIDName + GamePacket p2 = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`5<`w" + player->displayName + "`` left, `w" + std::to_string(getPlayersCountInWorld(player->currentWorld)) + "`` others here>``")); + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) { + { + + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + } + { + + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(currentPeer, 0, packet2); + + } + } + } + delete p.data; + delete p2.data; + } + + void sendChatMessage(ENetPeer* peer, int netID, string message) + { + if (message.length() == 0) return; + ENetPeer * currentPeer; + string name = ""; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (((PlayerInfo*)(currentPeer->data))->netID == netID) + name = ((PlayerInfo*)(currentPeer->data))->displayName; + + } + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`o<" + name + "`o> " + message)); + GamePacket p2 = packetEnd(appendIntx(appendString(appendIntx(appendString(createPacket(), "OnTalkBubble"), netID), message), 0)); + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) + { + + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(currentPeer, 0, packet); + + //enet_host_flush(server); + + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet2); + + //enet_host_flush(server); + } + } + delete p.data; + delete p2.data; + } + + void sendWho(ENetPeer* peer) + { + ENetPeer * currentPeer; + string name = ""; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) + { + GamePacket p2 = packetEnd(appendIntx(appendString(appendIntx(appendString(createPacket(), "OnTalkBubble"), ((PlayerInfo*)(currentPeer->data))->netID), ((PlayerInfo*)(currentPeer->data))->displayName), 1)); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(peer, 0, packet2); + delete p2.data; + //enet_host_flush(server); + } + } + } + + void sendWorld(ENetPeer* peer, WorldInfo* worldInfo) + { +#ifdef TOTAL_LOG + cout << "Entering some world..." << endl; +#endif + ((PlayerInfo*)(peer->data))->joinClothesUpdated = false; + string asdf = "0400000004A7379237BB2509E8E0EC04F8720B050000000000000000FBBB0000010000007D920100FDFDFDFD04000000040000000000000000000000070000000000"; // 0400000004A7379237BB2509E8E0EC04F8720B050000000000000000FBBB0000010000007D920100FDFDFDFD04000000040000000000000000000000080000000000000000000000000000000000000000000000000000000000000048133A0500000000BEBB0000070000000000 + string worldName = worldInfo->name; + int xSize = worldInfo->width; + int ySize = worldInfo->height; + int square = xSize*ySize; + __int16 nameLen = worldName.length(); + int payloadLen = asdf.length() / 2; + int dataLen = payloadLen + 2 + nameLen + 12 + (square * 8) + 4; + int allocMem = payloadLen + 2 + nameLen + 12 + (square * 8) + 4 + 16000; + BYTE* data = new BYTE[allocMem]; + for (int i = 0; i < asdf.length(); i += 2) + { + char x = ch2n(asdf[i]); + x = x << 4; + x += ch2n(asdf[i + 1]); + memcpy(data + (i / 2), &x, 1); + } + int zero = 0; + __int16 item = 0; + int smth = 0; + for (int i = 0; i < square * 8; i += 4) memcpy(data + payloadLen + i + 14 + nameLen, &zero, 4); + for (int i = 0; i < square * 8; i += 8) memcpy(data + payloadLen + i + 14 + nameLen, &item, 2); + memcpy(data + payloadLen, &nameLen, 2); + memcpy(data + payloadLen + 2, worldName.c_str(), nameLen); + memcpy(data + payloadLen + 2 + nameLen, &xSize, 4); + memcpy(data + payloadLen + 6 + nameLen, &ySize, 4); + memcpy(data + payloadLen + 10 + nameLen, &square, 4); + BYTE* blockPtr = data + payloadLen + 14 + nameLen; + for (int i = 0; i < square; i++) { + if ((worldInfo->items[i].foreground == 0) || (worldInfo->items[i].foreground == 2) || (worldInfo->items[i].foreground == 8) || (worldInfo->items[i].foreground == 100)/* || (worldInfo->items[i].foreground%2)*/) + { + memcpy(blockPtr, &worldInfo->items[i].foreground, 2); + int type = 0x00000000; + // type 1 = locked + if (worldInfo->items[i].water) + type |= 0x04000000; + if (worldInfo->items[i].glue) + type |= 0x08000000; + if (worldInfo->items[i].fire) + type |= 0x10000000; + if (worldInfo->items[i].red) + type |= 0x20000000; + if (worldInfo->items[i].green) + type |= 0x40000000; + if (worldInfo->items[i].blue) + type |= 0x80000000; + + // int type = 0x04000000; = water + // int type = 0x08000000 = glue + // int type = 0x10000000; = fire + // int type = 0x20000000; = red color + // int type = 0x40000000; = green color + // int type = 0x80000000; = blue color + memcpy(blockPtr + 4, &type, 4); + /*if (worldInfo->items[i].foreground % 2) + { + blockPtr += 6; + }*/ + } + else + { + memcpy(blockPtr, &zero, 2); + } + memcpy(blockPtr + 2, &worldInfo->items[i].background, 2); + blockPtr += 8; + /*if (blockPtr - data < allocMem - 2000) // realloc + { + int wLen = blockPtr - data; + BYTE* oldData = data; + + data = new BYTE[allocMem + 16000]; + memcpy(data, oldData, allocMem); + allocMem += 16000; + delete oldData; + blockPtr = data + wLen; + + }*/ + } + memcpy(data + dataLen - 4, &smth, 4); + ENetPacket * packet2 = enet_packet_create(data, + dataLen, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet2); + //enet_host_flush(server); + for (int i = 0; i < square; i++) { + if ((worldInfo->items[i].foreground == 0) || (worldInfo->items[i].foreground == 2) || (worldInfo->items[i].foreground == 8) || (worldInfo->items[i].foreground == 100)) + ; // nothing + else + { + PlayerMoving data; + //data.packetType = 0x14; + data.packetType = 0x3; + + //data.characterState = 0x924; // animation + data.characterState = 0x0; // animation + data.x = i%worldInfo->width; + data.y = i/worldInfo->height; + data.punchX = i%worldInfo->width; + data.punchY = i / worldInfo->width; + data.XSpeed = 0; + data.YSpeed = 0; + data.netID = -1; + data.plantingTree = worldInfo->items[i].foreground; + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE); + } + } + ((PlayerInfo*)(peer->data))->currentWorld = worldInfo->name; + delete data; + + } + + void sendAction(ENetPeer* peer, int netID, string action) + { + ENetPeer * currentPeer; + string name = ""; + GamePacket p2 = packetEnd(appendString(appendString(createPacket(), "OnAction"), action)); + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) { + + memcpy(p2.data + 8, &netID, 4); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(currentPeer, 0, packet2); + + //enet_host_flush(server); + } + } + delete p2.data; + } + + + // droping items WorldObjectMap::HandlePacket + void sendDrop(ENetPeer* peer, int netID, int x, int y, int item, int count, BYTE specialEffect) + { + if (item >= 7068) return; + if (item < 0) return; + ENetPeer * currentPeer; + string name = ""; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) { + PlayerMoving data; + data.packetType = 14; + data.x = x; + data.y = y; + data.netID = netID; + data.plantingTree = item; + float val = count; // item count + BYTE val2 = specialEffect; + + BYTE* raw = packPlayerMoving(&data); + memcpy(raw + 16, &val, 4); + memcpy(raw + 1, &val2, 1); + + SendPacketRaw(4, raw, 56, 0, currentPeer, ENET_PACKET_FLAG_RELIABLE); + } + } + } + + void sendState(ENetPeer* peer) { + //return; // TODO + PlayerInfo* info = ((PlayerInfo*)(peer->data)); + int netID = info->netID; + ENetPeer * currentPeer; + int state = getState(info); + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (isHere(peer, currentPeer)) { + PlayerMoving data; + data.packetType = 0x14; + data.characterState = 0; // animation + data.x = 1000; + data.y = 100; + data.punchX = 0; + data.punchY = 0; + data.XSpeed = 300; + data.YSpeed = 600; + data.netID = netID; + data.plantingTree = state; + BYTE* raw = packPlayerMoving(&data); + int var = 0x808000; // placing and breking + memcpy(raw+1, &var, 3); + SendPacketRaw(4, raw, 56, 0, currentPeer, ENET_PACKET_FLAG_RELIABLE); + } + } + // TODO + } + + + + void sendWorldOffers(ENetPeer* peer) + { + if (!((PlayerInfo*)(peer->data))->isIn) return; + vector worlds = worldDB.getRandomWorlds(); + string worldOffers = "default|"; + if (worlds.size() > 0) { + worldOffers += worlds[0].name; + } + + worldOffers += "\nadd_button|Showing: `wBest Worlds``|_catselect_|0.6|3529161471|\n"; + for (int i = 0; i < worlds.size(); i++) { + worldOffers += "add_floater|"+worlds[i].name+"|"+std::to_string(getPlayersCountInWorld(worlds[i].name))+"|0.55|3529161471\n"; + } + //GamePacket p3 = packetEnd(appendString(appendString(createPacket(), "OnRequestWorldSelectMenu"), "default|GO FOR IT\nadd_button|Showing: `wFake Worlds``|_catselect_|0.6|3529161471|\nadd_floater|Subscribe|5|0.55|3529161471\nadd_floater|Growtopia|4|0.52|4278190335\nadd_floater|Noobs|150|0.49|3529161471\nadd_floater|...|3|0.49|3529161471\nadd_floater|`6:O :O :O``|2|0.46|3529161471\nadd_floater|SEEMS TO WORK|2|0.46|3529161471\nadd_floater|?????|1|0.43|3529161471\nadd_floater|KEKEKEKEK|13|0.7|3417414143\n")); + //for (int i = 0; i < p.len; i++) cout << (int)*(p.data + i) << " "; + GamePacket p3 = packetEnd(appendString(appendString(createPacket(), "OnRequestWorldSelectMenu"), worldOffers)); + ENetPacket * packet3 = enet_packet_create(p3.data, + p3.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet3); + delete p3.data; + //enet_host_flush(server); + } + + + + + + BOOL WINAPI HandlerRoutine(DWORD dwCtrlType) + { + saveAllWorlds(); + return FALSE; + } + + /* + action|log +msg|`4UPDATE REQUIRED!`` : The `$V2.981`` update is now available for your device. Go get it! You'll need to install it before you can play online. +[DBG] Some text is here: action|set_url +url|http://ubistatic-a.akamaihd.net/0098/20180909/GrowtopiaInstaller.exe +label|Download Latest Version + */ +int _tmain(int argc, _TCHAR* argv[]) +{ + cout << "Growtopia private server (c) Growtopia Noobs" << endl; + enet_initialize(); + if (atexit(saveAllWorlds)) { + cout << "Worlds won't be saved for this session..." << endl; + } + /*if (RegisterApplicationRestart(L" -restarted", 0) == S_OK) + { + cout << "Autorestart is ready" << endl; + } + else { + cout << "Binding autorestart failed!" << endl; + } + Sleep(65000); + int* p = NULL; + *p = 5;*/ + SetConsoleCtrlHandler(HandlerRoutine, true); + + // load items.dat + { + std::ifstream file("items.dat", std::ios::binary | std::ios::ate); + itemsDatSize = file.tellg(); + + + itemsDat = new BYTE[60 + itemsDatSize]; + string asdf = "0400000010000000FFFFFFFF000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + for (int i = 0; i < asdf.length(); i += 2) + { + char x = ch2n(asdf[i]); + x = x << 4; + x += ch2n(asdf[i + 1]); + memcpy(itemsDat + (i / 2), &x, 1); + if (asdf.length() > 60 * 2) throw 0; + } + memcpy(itemsDat + 56, &itemsDatSize, 4); + file.seekg(0, std::ios::beg); + + if (file.read((char*)(itemsDat + 60), itemsDatSize)) + { + cout << "Updating items data suecess!" << endl; + + } + else { + cout << "Updating items data failed!" << endl; + } + } + + + //world = generateWorld(); + worldDB.get("TEST"); + worldDB.get("MAIN"); + worldDB.get("NEW"); + worldDB.get("ADMIN"); + ENetAddress address; + /* Bind the server to the default localhost. */ + /* A specific host address can be specified by */ + enet_address_set_host (&address, "0.0.0.0"); + //address.host = ENET_HOST_ANY; + /* Bind the server to port 1234. */ + address.port = 17091; + server = enet_host_create(&address /* the address to bind the server host to */, + 1024 /* allow up to 32 clients and/or outgoing connections */, + 10 /* allow up to 2 channels to be used, 0 and 1 */, + 0 /* assume any amount of incoming bandwidth */, + 0 /* assume any amount of outgoing bandwidth */); + if (server == NULL) + { + fprintf(stderr, + "An error occurred while trying to create an ENet server host.\n"); + while (1); + exit(EXIT_FAILURE); + } + server->checksum = enet_crc32; + enet_host_compress_with_range_coder(server); + + cout << "Building items database..." << endl; + buildItemsDatabase(); + cout << "Database is built!" << endl; + + ENetEvent event; + /* Wait up to 1000 milliseconds for an event. */ + while (true) + while (enet_host_service(server, &event, 1000) > 0) + { + ENetPeer* peer = event.peer; + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + { +#ifdef TOTAL_LOG + printf("A new client connected.\n"); +#endif + /* Store any relevant client information here. */ + //event.peer->data = "Client information"; + ENetPeer * currentPeer; + int count = 0; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (currentPeer->address.host == peer->address.host) + count++; + } + + event.peer->data = new PlayerInfo; + if (count > 3) + { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`rToo much accounts are logged on from this IP. If you don't think so, then please let server relax and connect again in half minute or so.``")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + enet_peer_disconnect_later(peer, 0); + } + else { + sendData(peer, 1, 0, 0); + } + + + continue; + } + case ENET_EVENT_TYPE_RECEIVE: + { + if (((PlayerInfo*)(peer->data))->isUpdating) + { + cout << "packet drop" << endl; + continue; + } + /*printf("A packet of length %u containing %s was received from %s on channel %u.\n", + event.packet->dataLength, + event.packet->data, + event.peer->data, + event.channelID); + cout << (int)*event.packet->data << endl;*/ + //cout << text_encode(getPacketData((char*)event.packet->data)); + /*for (int i = 0; i < event.packet->dataLength; i++) + { + cout << event.packet->data[i]; + } + sendData(7, 0, 0); + string x = "eventType|0\neventName|102_PLAYER.AUTHENTICATION\nAuthenticated|0\nAuthentication_error|6\nDevice_Id|^^\nGrow_Id|0\nName|^^Elektronik\nWordlock_balance|0\n"; + //string x = "eventType | 0\neventName | 102_PLAYER.AUTHENTICATION\nAuthenticated | 0\nAuthentication_error | 6\nDevice_Id | ^^\nGrow_Id | 0\nName | ^^Elektronik\nWorldlock_balance | 0\n"; + sendData(6, (char*)x.c_str(), x.length()); + string y = "action|quit\n"; + sendData(3, (char*)y.c_str(), y.length()); + cout << endl; + string asdf = "0400000001000000FFFFFFFF0000000008000000000000000000000000000000000000000000000000000000000000000000000000000000400000000600020E0000004F6E53656E64546F5365727665720109ED4200000209834CED00030910887F0104020D0000003230392E35392E3139302E347C05090100000000C"; + //asdf = "0400000001000000FFFFFFFF000000000800000000000000000000000000000000000000000000000000000000000000000000000000000040000000060002220000004F6E53757065724D61696E53746172744163636570744C6F676F6E464232313131330109ED4200000209834CED00030910887F0104020D0000003230392E35392E3139302E347C05090100000000C"; + ENetPacket * packet = enet_packet_create(0, + asdf.length()/2, + ENET_PACKET_FLAG_RELIABLE); + for (int i = 0; i < asdf.length(); i += 2) + { + char x = ch2n(asdf[i]); + x = x << 4; + x += ch2n(asdf[i + 1]); + memcpy(packet->data + (i / 2), &x, 1); + } + enet_peer_send(peer, 0, packet); + enet_host_flush(server); + /* Clean up the packet now that we're done using it. */ + //enet_packet_destroy(event.packet); + //sendData(7, 0, 0); + int messageType = GetMessageTypeFromPacket(event.packet); + //cout << "Packet type is " << messageType << endl; + //cout << (event->packet->data+4) << endl; + WorldInfo* world = getPlyersWorld(peer); + switch (messageType) { + case 2: + { + //cout << GetTextPointerFromPacket(event.packet) << endl; + string cch = GetTextPointerFromPacket(event.packet); + string str = cch.substr(cch.find("text|") + 5, cch.length() - cch.find("text|") - 1); + if (cch.find("action|respawn") == 0) + { + int x = 3040; + int y = 736; + + if (!world) continue; + + for (int i = 0; i < world->width*world->height; i++) + { + if (world->items[i].foreground == 6) { + x = (i%world->width) * 32; + y = (i / world->width) * 32; + } + } + { + PlayerMoving data; + data.packetType = 0x0; + data.characterState = 0x924; // animation + data.x = x; + data.y = y; + data.punchX = -1; + data.punchY = -1; + data.XSpeed = 0; + data.YSpeed = 0; + data.netID = ((PlayerInfo*)(peer->data))->netID; + data.plantingTree = 0x0; + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE); + } + + { + int x = 3040; + int y = 736; + + for (int i = 0; i < world->width*world->height; i++) + { + if (world->items[i].foreground == 6) { + x = (i%world->width) * 32; + y = (i / world->width) * 32; + } + } + GamePacket p2 = packetEnd(appendFloat(appendString(createPacket(), "OnSetPos"), x,y)); + memcpy(p2.data + 8, &(((PlayerInfo*)(peer->data))->netID), 4); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(peer, 0, packet2); + delete p2.data; + //enet_host_flush(server); + } + { + int x = 3040; + int y = 736; + + for (int i = 0; i < world->width*world->height; i++) + { + if (world->items[i].foreground == 6) { + x = (i%world->width) * 32; + y = (i / world->width) * 32; + } + } + GamePacket p2 = packetEnd(appendIntx(appendString(createPacket(), "OnSetFreezeState"), 0)); + memcpy(p2.data + 8, &(((PlayerInfo*)(peer->data))->netID), 4); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(peer, 0, packet2); + delete p2.data; + //enet_host_flush(server); + } +#ifdef TOTAL_LOG + cout << "Respawning... " << endl; +#endif + } + if (cch.find("action|growid") == 0) + { +#ifndef REGISTRATION + { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Registration is not supported yet!")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } +#endif +#ifdef REGISTRATION + //GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnDialogRequest"), "set_default_color|`o\n\nadd_label_with_icon|big|`w" + itemDefs.at(id).name + "``|left|" + std::to_string(id) + "|\n\nadd_spacer|small|\nadd_textbox|" + itemDefs.at(id).description + "|left|\nadd_spacer|small|\nadd_quick_exit|\nadd_button|chc0|Close|noflags|0|0|\nnend_dialog|gazette||OK|")); + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnDialogRequest"), "set_default_color|`o\n\nadd_label_with_icon|big|`wGet your GrowID Now!``|left|32|\n\nadd_spacer|small|\nadd_text_input|username|GrowID: ||15|\nadd_text_input|password|Password: ||100|\nend_dialog|register|Cancel|OK|\n")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + enet_host_flush(server); + delete p.data; +#endif + } + if (cch.find("action|store") == 0) + { + GamePacket p2 = packetEnd(appendString(appendString(createPacket(), "OnStoreRequest"), "set_description_text|Welcome to the `2Growtopia Store``! Tap the item you'd like more info on.`o `wWant to get `5Supporter`` status? Any Gem purchase (or `57,000`` Gems earned with free `5Tapjoy`` offers) will make you one. You'll get new skin colors, the `5Recycle`` tool to convert unwanted items into Gems, and more bonuses!\nadd_button|iap_menu|Buy Gems|interface/large/store_buttons5.rttex||0|2|0|0||\nadd_button|subs_menu|Subscriptions|interface/large/store_buttons22.rttex||0|1|0|0||\nadd_button|token_menu|Growtoken Items|interface/large/store_buttons9.rttex||0|0|0|0||\nadd_button|pristine_forceps|`oAnomalizing Pristine Bonesaw``|interface/large/store_buttons20.rttex|Built to exacting specifications by GrowTech engineers to find and remove temporal anomalies from infected patients, and with even more power than Delicate versions! Note : The fragile anomaly - seeking circuitry in these devices is prone to failure and may break (though with less of a chance than a Delicate version)! Use with care!|0|3|3500|0||\nadd_button|itemomonth|`oItem Of The Month``|interface/large/store_buttons16.rttex|`2September 2018:`` `9Sorcerer's Tunic of Mystery!`` Capable of reflecting the true colors of the world around it, this rare tunic is made of captured starlight and aether. If you think knitting with thread is hard, just try doing it with moonbeams and magic! The result is worth it though, as these clothes won't just make you look amazing - you'll be able to channel their inherent power into blasts of cosmic energy!``|0|3|200000|0||\nadd_button|contact_lenses|`oContact Lens Pack``|interface/large/store_buttons22.rttex|Need a colorful new look? This pack includes 10 random Contact Lens colors (and may include Contact Lens Cleaning Solution, to return to your natural eye color)!|0|7|15000|0||\nadd_button|locks_menu|Locks And Stuff|interface/large/store_buttons3.rttex||0|4|0|0||\nadd_button|itempack_menu|Item Packs|interface/large/store_buttons3.rttex||0|3|0|0||\nadd_button|bigitems_menu|Awesome Items|interface/large/store_buttons4.rttex||0|6|0|0||\nadd_button|weather_menu|Weather Machines|interface/large/store_buttons5.rttex|Tired of the same sunny sky? We offer alternatives within...|0|4|0|0||\n")); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(peer, 0, packet2); + delete p2.data; + //enet_host_flush(server); + } + if (cch.find("action|info") == 0) + { + std::stringstream ss(cch); + std::string to; + int id = -1; + int count = -1; + while (std::getline(ss, to, '\n')) { + vector infoDat = explode("|", to); + if (infoDat.size() == 3) { + if (infoDat[1] == "itemID") id = atoi(infoDat[2].c_str()); + if (infoDat[1] == "count") count = atoi(infoDat[2].c_str()); + } + } + if (id == -1 || count == -1) continue; + if (itemDefs.size() < id || id < 0) continue; + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnDialogRequest"), "set_default_color|`o\n\nadd_label_with_icon|big|`w"+ itemDefs.at(id).name +"``|left|"+std::to_string(id)+"|\n\nadd_spacer|small|\nadd_textbox|"+ itemDefs.at(id).description +"|left|\nadd_spacer|small|\nadd_quick_exit|\nadd_button|chc0|Close|noflags|0|0|\nnend_dialog|gazette||OK|")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + //enet_host_flush(server); + delete p.data; + } + if (cch.find("action|dialog_return") == 0) + { + std::stringstream ss(cch); + std::string to; + string btn = ""; + bool isRegisterDialog = false; + string username = ""; + string password = ""; + while (std::getline(ss, to, '\n')) { + vector infoDat = explode("|", to); + if (infoDat.size() == 2) { + if (infoDat[0] == "buttonClicked") btn = infoDat[1]; + if (infoDat[0] == "dialog_name" && infoDat[1] == "register") + { + isRegisterDialog = true; + } + if (isRegisterDialog) { + if (infoDat[0] == "username") username = infoDat[1]; + if (infoDat[0] == "password") password = infoDat[1]; + } + } + } + if (btn == "worldPublic") if (((PlayerInfo*)(peer->data))->rawName == getPlyersWorld(peer)->owner) getPlyersWorld(peer)->isPublic = true; + if(btn == "worldPrivate") if (((PlayerInfo*)(peer->data))->rawName == getPlyersWorld(peer)->owner) getPlyersWorld(peer)->isPublic = false; +#ifdef REGISTRATION + if (isRegisterDialog) { + + int regState = PlayerDB::playerRegister(username, password); + if (regState == 1) { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`rYour account was created!``")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + GamePacket p2 = packetEnd(appendString(appendString(appendInt(appendString(createPacket(), "SetHasGrowID"), 1), username), password)); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet2); + + //enet_host_flush(server); + delete p2.data; + enet_peer_disconnect_later(peer, 0); + } + else if(regState==-1) { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`rCreation of account failed, because it already exists!``")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + } + else if (regState == -2) { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`rCreation of account failed, because name is too short!``")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + } + } +#endif + } + string dropText = "action|drop\n|itemID|"; + if (cch.find(dropText) == 0) + { + sendDrop(peer, -1, ((PlayerInfo*)(peer->data))->x + (32 * (((PlayerInfo*)(peer->data))->isRotatedLeft?-1:1)), ((PlayerInfo*)(peer->data))->y, atoi(cch.substr(dropText.length(), cch.length() - dropText.length() - 1).c_str()), 1, 0); + /*int itemID = atoi(cch.substr(dropText.length(), cch.length() - dropText.length() - 1).c_str()); + PlayerMoving data; + data.packetType = 14; + data.x = ((PlayerInfo*)(peer->data))->x; + data.y = ((PlayerInfo*)(peer->data))->y; + data.netID = -1; + data.plantingTree = itemID; + float val = 1; // item count + BYTE val2 = 0; // if 8, then geiger effect + + BYTE* raw = packPlayerMoving(&data); + memcpy(raw + 16, &val, 4); + memcpy(raw + 1, &val2, 1); + SendPacketRaw(4, raw, 56, 0, peer, ENET_PACKET_FLAG_RELIABLE);*/ + } + if (cch.find("text|") != std::string::npos){ + if (str == "/mod") + { + ((PlayerInfo*)(peer->data))->canWalkInBlocks = true; + sendState(peer); + /*PlayerMoving data; + data.packetType = 0x14; + data.characterState = 0x0; // animation + data.x = 1000; + data.y = 1; + data.punchX = 0; + data.punchY = 0; + data.XSpeed = 300; + data.YSpeed = 600; + data.netID = ((PlayerInfo*)(peer->data))->netID; + data.plantingTree = 0xFF; + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE);*/ + } + else if (str.substr(0, 7) == "/state ") + { + PlayerMoving data; + data.packetType = 0x14; + data.characterState = 0x0; // animation + data.x = 1000; + data.y = 0; + data.punchX = 0; + data.punchY = 0; + data.XSpeed = 300; + data.YSpeed = 600; + data.netID = ((PlayerInfo*)(peer->data))->netID; + data.plantingTree = atoi(str.substr(7, cch.length() - 7 - 1).c_str()); + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE); + } + else if (str == "/help"){ + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Supporteds comands are: /help, /mod, /unmod, /inventory, /item id, /team id, /color number, /who, /state number, /count, /sb message, /alt, /radio")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } + else if (str == "/count"){ + int count = 0; + ENetPeer * currentPeer; + string name = ""; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + count++; + } + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "There is "+std::to_string(count)+" people out of 1024 limit.")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } + else if (str.substr(0, 5) == "/asb "){ + if (!canSB(((PlayerInfo*)(peer->data))->rawName, ((PlayerInfo*)(peer->data))->tankIDPass)) continue; + cout << "ASB from " << ((PlayerInfo*)(peer->data))->rawName << "in world " << ((PlayerInfo*)(peer->data))->currentWorld << "with IP " << std::hex << peer->address.host << std::dec << " with message " << str.substr(5, cch.length() - 5 - 1) << endl; + GamePacket p = packetEnd(appendInt(appendString(appendString(appendString(appendString(createPacket(), "OnAddNotification"), "interface/atomic_button.rttex"), str.substr(4, cch.length() - 4 - 1).c_str()), "audio/hub_open.wav"), 0)); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + ENetPeer * currentPeer; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + enet_peer_send(currentPeer, 0, packet); + } + + //enet_host_flush(server); + delete p.data; + } + else if (str.substr(0, 4) == "/sb ") { + using namespace std::chrono; + if (((PlayerInfo*)(peer->data))->lastSB + 45000 < (duration_cast(system_clock::now().time_since_epoch())).count()) + { + ((PlayerInfo*)(peer->data))->lastSB = (duration_cast(system_clock::now().time_since_epoch())).count(); + } + else { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "You are spamming sb too fast, calm down.")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + continue; + } + + string name = ((PlayerInfo*)(peer->data))->displayName; + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`w** `5Super-Broadcast`` from `$`2" + name + "```` (in `$" + ((PlayerInfo*)(peer->data))->currentWorld + "``) ** :`` `# " + str.substr(4, cch.length() - 4 - 1))); + string text = "action|play_sfx\nfile|audio/beep.wav\ndelayMS|0\n"; + BYTE* data = new BYTE[5 + text.length()]; + BYTE zero = 0; + int type = 3; + memcpy(data, &type, 4); + memcpy(data + 4, text.c_str(), text.length()); + memcpy(data + 4 + text.length(), &zero, 1); + ENetPeer * currentPeer; + + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (!((PlayerInfo*)(currentPeer->data))->radio) + continue; + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(currentPeer, 0, packet); + + + + + ENetPacket * packet2 = enet_packet_create(data, + 5+text.length(), + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(currentPeer, 0, packet2); + + //enet_host_flush(server); + } + delete data; + delete p.data; + } + else if (str.substr(0, 6) == "/radio") { + GamePacket p; + if (((PlayerInfo*)(peer->data))->radio) { + p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "You now won't recieve broadcast anymore.")); + ((PlayerInfo*)(peer->data))->radio = false; + } else { + p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "You will now recieve broadcasts again.")); + ((PlayerInfo*)(peer->data))->radio = true; + } + + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } + else if (str.substr(0, 6) == "/reset"){ + if (!isSuperAdmin(((PlayerInfo*)(peer->data))->rawName, ((PlayerInfo*)(peer->data))->tankIDPass)) break; + cout << "Restart from " << ((PlayerInfo*)(peer->data))->displayName << endl; + GamePacket p = packetEnd(appendInt(appendString(appendString(appendString(appendString(createPacket(), "OnAddNotification"), "interface/science_button.rttex"), "Restarting soon!"), "audio/mp3/suspended.mp3"), 0)); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + ENetPeer * currentPeer; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + enet_peer_send(currentPeer, 0, packet); + } + delete p.data; + //enet_host_flush(server); + } + + /*else if (str.substr(0, 7) == "/clear "){ + if (!canClear(((PlayerInfo*)(peer->data))->rawName, ((PlayerInfo*)(peer->data))->tankIDPass)) continue; + cout << "World cleared by " << ((PlayerInfo*)(peer->data))->tankIDName << endl; + WorldInfo* wrld = getPlyersWorld(peer); + string wName = str.substr(4, cch.length() - 4 - 1); + for (auto & c : wName) c = toupper(c); + for (int i = 0; i < worlds.size(); i++) + { + if (wrld == NULL) continue; + if (wName == wrld->name) + { + worlds.at(i) = generateWorld(wrld->name, wrld->width, wrld->height); + ENetPeer * currentPeer; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (((PlayerInfo*)(currentPeer->data))->currentWorld == wrld->name) + { + sendWorld(currentPeer, &worlds.at(i)); + + int x = 3040; + int y = 736; + + for (int j = 0; j < worlds.at(i).width*worlds.at(i).height; j++) + { + if (worlds.at(i).items[j].foreground == 6) { + x = (j%worlds.at(i).width) * 32; + y = (j / worlds.at(i).width) * 32; + } + } + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnSpawn"), "spawn|avatar\nnetID|" + std::to_string(cId) + "\nuserID|" + std::to_string(cId) + "\ncolrect|0|0|20|30\nposXY|" + std::to_string(x) + "|" + std::to_string(y) + "\nname|``" + ((PlayerInfo*)(currentPeer->data))->tankIDName + "``\ncountry|" + ((PlayerInfo*)(currentPeer->data))->country + "\ninvis|0\nmstate|0\nsmstate|0\ntype|local\n")); + //for (int i = 0; i < p.len; i++) cout << (int)*(p.data + i) << " "; + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet); + + enet_host_flush(server); + delete p.data; + ((PlayerInfo*)(currentPeer->data))->netID = cId; + onPeerConnect(currentPeer); + cId++; + + sendInventory(((PlayerInfo*)(event.peer->data))->inventory); + } + + } + enet_host_flush(server); + } + } + } + else if (str.substr(0, 6) == "/clear"){ + if (!canClear(((PlayerInfo*)(peer->data))->rawName, ((PlayerInfo*)(peer->data))->tankIDPass)) continue; + cout << "World cleared by " << ((PlayerInfo*)(peer->data))->tankIDName << endl; + WorldInfo* wrld = getPlyersWorld(peer); + for (int i = 0; i < worlds.size(); i++) + { + if (wrld == NULL) continue; + if (&worlds.at(i) == wrld) + { + worlds.at(i) = generateWorld(wrld->name, wrld->width, wrld->height); + ENetPeer * currentPeer; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + if (((PlayerInfo*)(currentPeer->data))->currentWorld == wrld->name) + { + sendWorld(currentPeer, &worlds.at(i)); + + int x = 3040; + int y = 736; + + for (int j = 0; j < worlds.at(i).width*worlds.at(i).height; j++) + { + if (worlds.at(i).items[j].foreground == 6) { + x = (j%worlds.at(i).width) * 32; + y = (j / worlds.at(i).width) * 32; + } + } + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnSpawn"), "spawn|avatar\nnetID|" + std::to_string(cId) + "\nuserID|" + std::to_string(cId) + "\ncolrect|0|0|20|30\nposXY|" + std::to_string(x) + "|" + std::to_string(y) + "\nname|``" + ((PlayerInfo*)(currentPeer->data))->tankIDName + "``\ncountry|" + ((PlayerInfo*)(currentPeer->data))->country + "\ninvis|0\nmstate|0\nsmstate|0\ntype|local\n")); + //for (int i = 0; i < p.len; i++) cout << (int)*(p.data + i) << " "; + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet); + + enet_host_flush(server); + delete p.data; + ((PlayerInfo*)(currentPeer->data))->netID = cId; + onPeerConnect(currentPeer); + cId++; + + sendInventory(((PlayerInfo*)(event.peer->data))->inventory); + } + + } + enet_host_flush(server); + } + } + }*/ + else if (str == "/unmod") + { + ((PlayerInfo*)(peer->data))->canWalkInBlocks = false; + sendState(peer); + /*PlayerMoving data; + data.packetType = 0x14; + data.characterState = 0x0; // animation + data.x = 1000; + data.y = 1; + data.punchX = 0; + data.punchY = 0; + data.XSpeed = 300; + data.YSpeed = 600; + data.netID = ((PlayerInfo*)(peer->data))->netID; + data.plantingTree = 0x0; + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE);*/ + } + else if (str == "/alt") { + GamePacket p2 = packetEnd(appendInt(appendString(createPacket(), "OnSetBetaMode"), 1)); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet2); + delete p2.data; + //enet_host_flush(server); + } + else + if (str == "/inventory") + { + sendInventory(peer, ((PlayerInfo*)(peer->data))->inventory); + } else + if (str.substr(0,6) == "/item ") + { + PlayerInventory inventory; + InventoryItem item; + item.itemID = atoi(str.substr(6, cch.length() - 6 - 1).c_str()); + item.itemCount = 200; + inventory.items.push_back(item); + item.itemCount = 1; + item.itemID = 18; + inventory.items.push_back(item); + item.itemID = 32; + inventory.items.push_back(item); + sendInventory(peer, inventory); + } else + if (str.substr(0, 6) == "/team ") + { + int val = 0; + val = atoi(str.substr(6, cch.length() - 6 - 1).c_str()); + PlayerMoving data; + //data.packetType = 0x14; + data.packetType = 0x1B; + //data.characterState = 0x924; // animation + data.characterState = 0x0; // animation + data.x = 0; + data.y = 0; + data.punchX = val; + data.punchY = 0; + data.XSpeed = 0; + data.YSpeed = 0; + data.netID = ((PlayerInfo*)(peer->data))->netID; + data.plantingTree = 0; + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE); + + } else + if (str.substr(0, 7) == "/color ") + { + ((PlayerInfo*)(peer->data))->skinColor = atoi(str.substr(6, cch.length() - 6 - 1).c_str()); + sendClothes(peer); + } + if (str.substr(0, 4) == "/who") + { + sendWho(peer); + + } + if (str.length() && str[0] == '/') + { + sendAction(peer, ((PlayerInfo*)(peer->data))->netID, str); + } else if (str.length()>0) + { + sendChatMessage(peer, ((PlayerInfo*)(peer->data))->netID, str); + } + + } + if (!((PlayerInfo*)(event.peer->data))->isIn) + { + GamePacket p = packetEnd(appendString(appendString(appendString(appendString(appendInt(appendString(createPacket(), "OnSuperMainStartAcceptLogonFB211131ddf"), -407289376), "cdn.growtopiagame.com"), "cache/"), "cc.cz.madkite.freedom org.aqua.gg idv.aqua.bulldog com.cih.gamecih2 com.cih.gamecih com.cih.game_cih cn.maocai.gamekiller com.gmd.speedtime org.dax.attack com.x0.strai.frep com.x0.strai.free org.cheatengine.cegui org.sbtools.gamehack com.skgames.traffikrider org.sbtoods.gamehaca com.skype.ralder org.cheatengine.cegui.xx.multi1458919170111 com.prohiro.macro me.autotouch.autotouch com.cygery.repetitouch.free com.cygery.repetitouch.pro com.proziro.zacro com.slash.gamebuster"), "proto=42|choosemusic=audio/mp3/about_theme.mp3|active_holiday=0|")); + //for (int i = 0; i < p.len; i++) cout << (int)*(p.data + i) << " "; + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + //enet_host_flush(server); + delete p.data; + std::stringstream ss(GetTextPointerFromPacket(event.packet)); + std::string to; + while (std::getline(ss, to, '\n')){ + string id = to.substr(0, to.find("|")); + string act = to.substr(to.find("|") + 1, to.length() - to.find("|") - 1); + if (id == "tankIDName") + { + ((PlayerInfo*)(event.peer->data))->tankIDName = act; + ((PlayerInfo*)(event.peer->data))->haveGrowId = true; + } + else if(id == "tankIDPass") + { + ((PlayerInfo*)(event.peer->data))->tankIDPass = act; + } + else if(id == "requestedName") + { + ((PlayerInfo*)(event.peer->data))->requestedName = act; + } + else if (id == "country") + { + ((PlayerInfo*)(event.peer->data))->country = act; + } + } + if (!((PlayerInfo*)(event.peer->data))->haveGrowId) + { + ((PlayerInfo*)(event.peer->data))->rawName = ""; + ((PlayerInfo*)(event.peer->data))->displayName = "Fake " + PlayerDB::fixColors(((PlayerInfo*)(event.peer->data))->requestedName.substr(0, ((PlayerInfo*)(event.peer->data))->requestedName.length()>15?15:((PlayerInfo*)(event.peer->data))->requestedName.length())); + } + else { + ((PlayerInfo*)(event.peer->data))->rawName = PlayerDB::getProperName(((PlayerInfo*)(event.peer->data))->tankIDName); +#ifdef REGISTRATION + int logStatus = PlayerDB::playerLogin(peer, ((PlayerInfo*)(event.peer->data))->rawName, ((PlayerInfo*)(event.peer->data))->tankIDPass); + if (logStatus == 1) { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`rYou has successfully logged to your account!``")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + ((PlayerInfo*)(event.peer->data))->displayName = ((PlayerInfo*)(event.peer->data))->tankIDName; + } + else { + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "`rWrong username or password!``")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + enet_peer_disconnect_later(peer, 0); + } +#else + + ((PlayerInfo*)(event.peer->data))->displayName = PlayerDB::fixColors(((PlayerInfo*)(event.peer->data))->tankIDName.substr(0, ((PlayerInfo*)(event.peer->data))->tankIDName.length()>18 ? 18 : ((PlayerInfo*)(event.peer->data))->tankIDName.length())); + if (((PlayerInfo*)(event.peer->data))->displayName.length() < 3) ((PlayerInfo*)(event.peer->data))->displayName = "Person that don't know how name looks!"; +#endif + } + for (char c : ((PlayerInfo*)(event.peer->data))->displayName) if (c < 0x20 || c>0x7A) ((PlayerInfo*)(event.peer->data))->displayName = "Bad characters in name, remove them!"; + + if (((PlayerInfo*)(event.peer->data))->country.length() > 4) + { + ((PlayerInfo*)(event.peer->data))->country = "us"; + } + if (getAdminLevel(((PlayerInfo*)(event.peer->data))->rawName, ((PlayerInfo*)(event.peer->data))->tankIDPass) > 0) + { + ((PlayerInfo*)(event.peer->data))->country = "../cash_icon_overlay"; + } + /*GamePacket p3= packetEnd(appendString(appendString(createPacket(), "OnRequestWorldSelectMenu"), "default|GO FOR IT\nadd_button|Showing: `wFake Worlds``|_catselect_|0.6|3529161471|\nadd_floater|Subscribe|5|0.55|3529161471\nadd_floater|Growtopia|4|0.52|4278190335\nadd_floater|Noobs|150|0.49|3529161471\nadd_floater|...|3|0.49|3529161471\nadd_floater|`6:O :O :O``|2|0.46|3529161471\nadd_floater|SEEMS TO WORK|2|0.46|3529161471\nadd_floater|?????|1|0.43|3529161471\nadd_floater|KEKEKEKEK|13|0.7|3417414143\n")); + //for (int i = 0; i < p.len; i++) cout << (int)*(p.data + i) << " "; + ENetPacket * packet3 = enet_packet_create(p3.data, + p3.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet3); + enet_host_flush(server);*/ + + GamePacket p2 = packetEnd(appendString(appendString(appendInt(appendString(createPacket(), "SetHasGrowID"), ((PlayerInfo*)(event.peer->data))->haveGrowId), ((PlayerInfo*)(peer->data))->tankIDName), ((PlayerInfo*)(peer->data))->tankIDPass)); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet2); + delete p2.data; + + + } + string pStr = GetTextPointerFromPacket(event.packet); + //if (strcmp(GetTextPointerFromPacket(event.packet), "action|enter_game\n") == 0 && !((PlayerInfo*)(event.peer->data))->isIn) + if(pStr.substr(0, 17) == "action|enter_game" && !((PlayerInfo*)(event.peer->data))->isIn) + { +#ifdef TOTAL_LOG + cout << "And we are in!" << endl; +#endif + ENetPeer* currentPeer; + ((PlayerInfo*)(event.peer->data))->isIn = true; + /*for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Player `o" + ((PlayerInfo*)(event.peer->data))->tankIDName + "`o just entered game...")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet); + + enet_host_flush(server); + delete p.data; + }*/ + sendWorldOffers(peer); + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Server made by Growtopia Noobs, hosted by FakeHax and items from Nenkai.")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + //enet_host_flush(server); + delete p.data; + PlayerInventory inventory; + for (int i = 0; i < 200; i++) + { + InventoryItem it; + it.itemID = (i * 2) + 2; + it.itemCount = 200; + inventory.items.push_back(it); + } + ((PlayerInfo*)(event.peer->data))->inventory = inventory; + + { + //GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnDialogRequest"), "set_default_color|`o\n\nadd_label_with_icon|big|`wThe Growtopia Gazette``|left|5016|\n\nadd_spacer|small|\n\nadd_image_button|banner|interface/large/news_banner.rttex|noflags|||\n\nadd_spacer|small|\n\nadd_textbox|`wSeptember 10:`` `5Surgery Stars end!``|left|\n\nadd_spacer|small|\n\n\n\nadd_textbox|Hello Growtopians,|left|\n\nadd_spacer|small|\n\n\n\nadd_textbox|Surgery Stars is over! We hope you enjoyed it and claimed all your well-earned Summer Tokens!|left|\n\nadd_spacer|small|\n\nadd_spacer|small|\n\nadd_textbox|As we announced earlier, this month we are releasing the feature update a bit later, as we're working on something really cool for the monthly update and we're convinced that the wait will be worth it!|left|\n\nadd_spacer|small|\n\nadd_textbox|Check the Forum here for more information!|left|\n\nadd_spacer|small|\n\nadd_url_button|comment|`wSeptember Updates Delay``|noflags|https://www.growtopiagame.com/forums/showthread.php?510657-September-Update-Delay&p=3747656|Open September Update Delay Announcement?|0|0|\n\nadd_spacer|small|\n\nadd_spacer|small|\n\nadd_textbox|Also, we're glad to invite you to take part in our official Growtopia survey!|left|\n\nadd_spacer|small|\n\nadd_url_button|comment|`wTake Survey!``|noflags|https://ubisoft.ca1.qualtrics.com/jfe/form/SV_1UrCEhjMO7TKXpr?GID=26674|Open the browser to take the survey?|0|0|\n\nadd_spacer|small|\n\nadd_textbox|Click on the button above and complete the survey to contribute your opinion to the game and make Growtopia even better! Thanks in advance for taking the time, we're looking forward to reading your feedback!|left|\n\nadd_spacer|small|\n\nadd_spacer|small|\n\nadd_textbox|And for those who missed PAW, we made a special video sneak peek from the latest PAW fashion show, check it out on our official YouTube channel! Yay!|left|\n\nadd_spacer|small|\n\nadd_url_button|comment|`wPAW 2018 Fashion Show``|noflags|https://www.youtube.com/watch?v=5i0IcqwD3MI&feature=youtu.be|Open the Growtopia YouTube channel for videos and tutorials?|0|0|\n\nadd_spacer|small|\n\nadd_textbox|Lastly, check out other September updates:|left|\n\nadd_spacer|small|\n\nadd_label_with_icon|small|IOTM: The Sorcerer's Tunic of Mystery|left|24|\n\nadd_label_with_icon|small|New Legendary Summer Clash Branch|left|24|\n\nadd_spacer|small|\n\nadd_textbox|`$- The Growtopia Team``|left|\n\nadd_spacer|small|\n\nadd_spacer|small|\n\n\n\n\n\nadd_url_button|comment|`wOfficial YouTube Channel``|noflags|https://www.youtube.com/c/GrowtopiaOfficial|Open the Growtopia YouTube channel for videos and tutorials?|0|0|\n\nadd_url_button|comment|`wSeptember's IOTM: `8Sorcerer's Tunic of Mystery!````|noflags|https://www.growtopiagame.com/forums/showthread.php?450065-Item-of-the-Month&p=3392991&viewfull=1#post3392991|Open the Growtopia website to see item of the month info?|0|0|\n\nadd_spacer|small|\n\nadd_label_with_icon|small|`4WARNING:`` `5Drop games/trust tests`` and betting games (like `5Casinos``) are not allowed and will result in a ban!|left|24|\n\nadd_label_with_icon|small|`4WARNING:`` Using any kind of `5hacked client``, `5spamming/text pasting``, or `5bots`` (even with an alt) will likely result in losing `5ALL`` your accounts. Seriously.|left|24|\n\nadd_label_with_icon|small|`4WARNING:`` `5NEVER enter your GT password on a website (fake moderator apps, free gemz, etc) - it doesn't work and you'll lose all your stuff!|left|24|\n\nadd_spacer|small|\n\nadd_url_button|comment|`wGrowtopia on Facebook``|noflags|http://growtopiagame.com/facebook|Open the Growtopia Facebook page in your browser?|0|0|\n\nadd_spacer|small|\n\nadd_button|rules|`wHelp - Rules - Privacy Policy``|noflags|0|0|\n\n\nadd_quick_exit|\n\nadd_spacer|small|\nadd_url_button|comment|`wVisit Growtopia Forums``|noflags|http://www.growtopiagame.com/forums|Visit the Growtopia forums?|0|0|\nadd_spacer|small|\nadd_url_button||`wWOTD: `1THELOSTGOLD`` by `#iWasToD````|NOFLAGS|OPENWORLD|THELOSTGOLD|0|0|\nadd_spacer|small|\nadd_url_button||`wVOTW: `1Yodeling Kid - Growtopia Animation``|NOFLAGS|https://www.youtube.com/watch?v=UMoGmnFvc58|Watch 'Yodeling Kid - Growtopia Animation' by HyerS on YouTube?|0|0|\nend_dialog|gazette||OK|")); + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnDialogRequest"), "set_default_color|`o\n\nadd_label_with_icon|big|`wThe Growtopia Gazette``|left|5016|\n\nadd_spacer|small|\nadd_label_with_icon|small|`4WARNING:`` `5Worlds (and accounts)`` might be deleted at any time if database issues appear (once per day or week).|left|4|\nadd_label_with_icon|small|`4WARNING:`` `5Accounts`` are in beta, bugs may appear and they will be probably deleted often, because of new accounts updates, which will cause database incompatibility.|left|4|\nadd_spacer|small|\n\nadd_url_button||``Watch: `1Watch newsest video about GT Private Server``|NOFLAGS|https://www.youtube.com/watch?v=_3avlDDYBBY|Open link?|0|0|\nadd_url_button||``Channel: `1Watch Growtopia Noobs channel``|NOFLAGS|https://www.youtube.com/channel/UCLXtuoBlrXFDRtFU8vPy35g|Open link?|0|0|\nadd_url_button||``Items: `1Items database by Nenkai``|NOFLAGS|https://raw.githubusercontent.com/Nenkai/GrowtopiaItemDatabase/master/GrowtopiaItemDatabase/CoreData.txt|Open link?|0|0|\nadd_url_button||``Discord: `1Community discord about GT Private Server``|NOFLAGS|https://discord.gg/8WUTs4v|Open link?|0|0|\nadd_quick_exit|\nadd_button|chc0|Close|noflags|0|0|\nnend_dialog|gazette||OK|")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + + //enet_host_flush(server); + delete p.data; + } + } + if (strcmp(GetTextPointerFromPacket(event.packet), "action|refresh_item_data\n") == 0) + { + if (itemsDat != NULL) { + ENetPacket * packet = enet_packet_create(itemsDat, + itemsDatSize + 60, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + ((PlayerInfo*)(peer->data))->isUpdating = true; + enet_peer_disconnect_later(peer, 0); + //enet_host_flush(server); + } + // TODO FIX refresh_item_data ^^^^^^^^^^^^^^ + } + break; + } + default: + cout << "Unknown packet type " << messageType << endl; + break; + case 3: + { + //cout << GetTextPointerFromPacket(event.packet) << endl; + std::stringstream ss(GetTextPointerFromPacket(event.packet)); + std::string to; + bool isJoinReq = false; + while (std::getline(ss, to, '\n')) { + string id = to.substr(0, to.find("|")); + string act = to.substr(to.find("|") + 1, to.length() - to.find("|") - 1); + if (id == "name" && isJoinReq) + { +#ifdef TOTAL_LOG + cout << "Entering some world..." << endl; +#endif + try { + WorldInfo info = worldDB.get(act); + sendWorld(peer, &info); + /*string asdf = "0400000004A7379237BB2509E8E0EC04F8720B050000000000000000FBBB0000010000007D920100FDFDFDFD04000000040000000000000000000000070000000000"; // 0400000004A7379237BB2509E8E0EC04F8720B050000000000000000FBBB0000010000007D920100FDFDFDFD04000000040000000000000000000000080000000000000000000000000000000000000000000000000000000000000048133A0500000000BEBB0000070000000000 + string worldName = "TEST"; + int xSize=100; + int ySize=60; + int square = xSize*ySize; + __int16 nameLen = worldName.length(); + int payloadLen = asdf.length() / 2; + int dataLen = payloadLen + 2 + nameLen + 12 + (square * 8)+4; + BYTE* data = new BYTE[dataLen]; + for (int i = 0; i < asdf.length(); i += 2) + { + char x = ch2n(asdf[i]); + x = x << 4; + x += ch2n(asdf[i + 1]); + memcpy(data + (i / 2), &x, 1); + } + int zero = 0; + __int16 item = 0; + int smth = 0; + for (int i = 0; i < square * 8; i += 4) memcpy(data + payloadLen + i + 14 + nameLen, &zero, 4); + for (int i = 0; i < square * 8; i += 8) memcpy(data + payloadLen + i + 14 + nameLen, &item, 2); + memcpy(data + payloadLen, &nameLen, 2); + memcpy(data + payloadLen + 2, worldName.c_str(), nameLen); + memcpy(data + payloadLen + 2 + nameLen, &xSize, 4); + memcpy(data + payloadLen + 6 + nameLen, &ySize, 4); + memcpy(data + payloadLen + 10 + nameLen, &square, 4); + for (int i = 0; i < 1700; i++) { + __int16 bed = 100; + memcpy(data + payloadLen + (i * 8) + 14 + nameLen + (8 * 100 * 37), &bed, 2); + } + for (int i = 0; i < 600; i++) { + __int16 bed = 8; + memcpy(data + payloadLen + (i*8) + 14 + nameLen + (8*100*54), &bed, 2); + } + memcpy(data + dataLen-4, &smth, 4); + ENetPacket * packet2 = enet_packet_create(data, + dataLen, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet2); + enet_host_flush(server);*/ + + int x = 3040; + int y = 736; + + for (int j = 0; j < info.width*info.height; j++) + { + if (info.items[j].foreground == 6) { + x = (j%info.width) * 32; + y = (j / info.width) * 32; + } + } + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnSpawn"), "spawn|avatar\nnetID|" + std::to_string(cId) + "\nuserID|" + std::to_string(cId) + "\ncolrect|0|0|20|30\nposXY|" + std::to_string(x) + "|" + std::to_string(y) + "\nname|``" + ((PlayerInfo*)(event.peer->data))->displayName + "``\ncountry|" + ((PlayerInfo*)(event.peer->data))->country + "\ninvis|0\nmstate|0\nsmstate|0\ntype|local\n")); + //for (int i = 0; i < p.len; i++) cout << (int)*(p.data + i) << " "; + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + //enet_host_flush(server); + delete p.data; + ((PlayerInfo*)(event.peer->data))->netID = cId; + onPeerConnect(peer); + cId++; + + sendInventory(peer, ((PlayerInfo*)(event.peer->data))->inventory); + + + + /*int resx = 95; + int resy = 23;*/ + + /*for (int i = 0; i < world.width*world.height; i++) + { + if (world.items[i].foreground == 6) { + resx = i%world.width; + resy = i / world.width; + } + } + + GamePacket p2 = packetEnd(appendInt(appendString(createPacket(), "SetRespawnPos"), resx + (world.width*resy))); + memcpy(p2.data + 8, &(((PlayerInfo*)(event.peer->data))->netID), 4); + ENetPacket * packet2 = enet_packet_create(p2.data, + p2.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + enet_host_flush(server);*/ + } + catch (int e) { + if (e == 1) { + ((PlayerInfo*)(peer->data))->currentWorld = "EXIT"; + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "You are in EXIT!")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } + else if (e == 2) { + ((PlayerInfo*)(peer->data))->currentWorld = "EXIT"; + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "You have entered bad characters to world name!")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } + else if (e == 3) { + ((PlayerInfo*)(peer->data))->currentWorld = "EXIT"; + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "You can't go to EXIT!")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } + else { + ((PlayerInfo*)(peer->data))->currentWorld = "EXIT"; + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Unknown error while entering world!")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet); + delete p.data; + //enet_host_flush(server); + } + } + } + if (id == "action") + { + + if (act == "join_request") + { + isJoinReq = true; + } + if (act == "quit_to_exit") + { + sendPlayerLeave(peer, (PlayerInfo*)(event.peer->data)); + ((PlayerInfo*)(peer->data))->currentWorld = "EXIT"; + sendWorldOffers(peer); + + } + if (act == "quit") + { + enet_peer_disconnect_later(peer, 0); + } + } + } + break; + } + case 4: + { + { + BYTE* tankUpdatePacket = GetStructPointerFromTankPacket(event.packet); + + if (tankUpdatePacket) + { + PlayerMoving* pMov = unpackPlayerMoving(tankUpdatePacket); + switch (pMov->packetType) + { + case 0: + ((PlayerInfo*)(event.peer->data))->x = pMov->x; + ((PlayerInfo*)(event.peer->data))->y = pMov->y; + ((PlayerInfo*)(event.peer->data))->isRotatedLeft = pMov->characterState & 0x10; + sendPData(peer, pMov); + if (!((PlayerInfo*)(peer->data))->joinClothesUpdated) + { + ((PlayerInfo*)(peer->data))->joinClothesUpdated = true; + updateAllClothes(peer); + } + break; + + default: + break; + } + PlayerMoving *data2 = unpackPlayerMoving(tankUpdatePacket); + //cout << data2->packetType << endl; + if (data2->packetType == 11) + { + //cout << pMov->x << ";" << pMov->y << ";" << pMov->plantingTree << ";" << pMov->punchX << endl; + //sendDrop(((PlayerInfo*)(event.peer->data))->netID, ((PlayerInfo*)(event.peer->data))->x, ((PlayerInfo*)(event.peer->data))->y, pMov->punchX, 1, 0); + // lets take item + } + if (data2->packetType == 7) + { + //cout << pMov->x << ";" << pMov->y << ";" << pMov->plantingTree << ";" << pMov->punchX << endl; + /*GamePacket p3 = packetEnd(appendString(appendString(createPacket(), "OnRequestWorldSelectMenu"), "default|GO FOR IT\nadd_button|Showing: `wFake Worlds``|_catselect_|0.6|3529161471|\nadd_floater|Subscribe|5|0.55|3529161471\nadd_floater|Growtopia|4|0.52|4278190335\nadd_floater|Noobs|150|0.49|3529161471\nadd_floater|...|3|0.49|3529161471\nadd_floater|`6:O :O :O``|2|0.46|3529161471\nadd_floater|SEEMS TO WORK|2|0.46|3529161471\nadd_floater|?????|1|0.43|3529161471\nadd_floater|KEKEKEKEK|13|0.7|3417414143\n")); + //for (int i = 0; i < p.len; i++) cout << (int)*(p.data + i) << " "; + ENetPacket * packet3 = enet_packet_create(p3.data, + p3.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(peer, 0, packet3); + enet_host_flush(server);*/ + sendWorldOffers(peer); + // lets take item + } + if (data2->packetType == 10) + { + //cout << pMov->x << ";" << pMov->y << ";" << pMov->plantingTree << ";" << pMov->punchX << ";" << pMov->punchY << ";" << pMov->characterState << endl; + ItemDefinition def; + try { + def = getItemDef(pMov->plantingTree); + } + catch (int e) { + goto END_CLOTHSETTER_FORCE; + } + + switch (def.clothType) { + case 0: + if (((PlayerInfo*)(event.peer->data))->cloth0 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth0 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth0 = pMov->plantingTree; + break; + case 1: + if (((PlayerInfo*)(event.peer->data))->cloth1 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth1 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth1 = pMov->plantingTree; + break; + case 2: + if (((PlayerInfo*)(event.peer->data))->cloth2 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth2 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth2 = pMov->plantingTree; + break; + case 3: + if (((PlayerInfo*)(event.peer->data))->cloth3 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth3 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth3 = pMov->plantingTree; + break; + case 4: + if (((PlayerInfo*)(event.peer->data))->cloth4 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth4 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth4 = pMov->plantingTree; + break; + case 5: + if (((PlayerInfo*)(event.peer->data))->cloth5 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth5 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth5 = pMov->plantingTree; + break; + case 6: + if (((PlayerInfo*)(event.peer->data))->cloth6 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth6 = 0; + ((PlayerInfo*)(event.peer->data))->canDoubleJump = false; + sendState(peer); + break; + } + { + ((PlayerInfo*)(event.peer->data))->cloth6 = pMov->plantingTree; + int item = pMov->plantingTree; + if (item == 156 || item == 362 || item == 678 || item == 736 || item == 818 || item == 1206 || item == 1460 || item == 1550 || item == 1574 || item == 1668 || item == 1672 || item == 1674 || item == 1784 || item == 1824 || item == 1936 || item == 1938 || item == 1970 || item == 2254 || item == 2256 || item == 2258 || item == 2260 || item == 2262 || item == 2264 || item == 2390 || item == 2392 || item == 3120 || item == 3308 || item == 3512 || item == 4534 || item == 4986 || item == 5754 || item == 6144 || item == 6334 || item == 6694 || item == 6818 || item == 6842 || item == 1934 || item == 3134 || item == 6004 || item == 1780 || item == 2158 || item == 2160 || item == 2162 || item == 2164 || item == 2166 || item == 2168 || item == 2438 || item == 2538 || item == 2778 || item == 3858 || item == 350 || item == 998 || item == 1738 || item == 2642 || item == 2982 || item == 3104 || item == 3144 || item == 5738 || item == 3112 || item == 2722 || item == 3114 || item == 4970 || item == 4972 || item == 5020 || item == 6284 || item == 4184 || item == 4628 || item == 5322 || item == 4112 || item == 4114 || item == 3442) { + ((PlayerInfo*)(event.peer->data))->canDoubleJump = true; + } + else { + ((PlayerInfo*)(event.peer->data))->canDoubleJump = false; + } + // ^^^^ wings + sendState(peer); + } + break; + case 7: + if (((PlayerInfo*)(event.peer->data))->cloth7 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth7 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth7 = pMov->plantingTree; + break; + case 8: + if (((PlayerInfo*)(event.peer->data))->cloth8 == pMov->plantingTree) + { + ((PlayerInfo*)(event.peer->data))->cloth8 = 0; + break; + } + ((PlayerInfo*)(event.peer->data))->cloth8 = pMov->plantingTree; + break; + default: +#ifdef TOTAL_LOG + cout << "Invalid item activated: " << pMov->plantingTree << " by " << ((PlayerInfo*)(event.peer->data))->displayName << endl; +#endif + break; + } + sendClothes(peer); + // activate item + END_CLOTHSETTER_FORCE:; + } + if (data2->packetType == 18) + { + sendPData(peer, pMov); + // add talk buble + } + if (data2->punchX != -1 && data2->punchY != -1) { + //cout << data2->packetType << endl; + if (data2->packetType == 3) + { + sendTileUpdate(data2->punchX, data2->punchY, data2->plantingTree, ((PlayerInfo*)(event.peer->data))->netID, peer); + } + else { + + } + /*PlayerMoving data; + //data.packetType = 0x14; + data.packetType = 0x3; + //data.characterState = 0x924; // animation + data.characterState = 0x0; // animation + data.x = data2->punchX; + data.y = data2->punchY; + data.punchX = data2->punchX; + data.punchY = data2->punchY; + data.XSpeed = 0; + data.YSpeed = 0; + data.netID = ((PlayerInfo*)(event.peer->data))->netID; + data.plantingTree = data2->plantingTree; + SendPacketRaw(4, packPlayerMoving(&data), 56, 0, peer, ENET_PACKET_FLAG_RELIABLE); + cout << "Tile update at: " << data2->punchX << "x" << data2->punchY << endl;*/ + + } + delete data2; + delete pMov; + } + + else { + cout << "Got bad tank packet"; + } + /*char buffer[2048]; + for (int i = 0; i < event->packet->dataLength; i++) + { + sprintf(&buffer[2 * i], "%02X", event->packet->data[i]); + } + cout << buffer;*/ + } + } + break; + case 5: + break; + case 6: + //cout << GetTextPointerFromPacket(event.packet) << endl; + break; + } + enet_packet_destroy(event.packet); + break; + } + case ENET_EVENT_TYPE_DISCONNECT: +#ifdef TOTAL_LOG + printf("Peer disconnected.\n"); +#endif + /* Reset the peer's client information. */ + /*ENetPeer* currentPeer; + for (currentPeer = server->peers; + currentPeer < &server->peers[server->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + + GamePacket p = packetEnd(appendString(appendString(createPacket(), "OnConsoleMessage"), "Player `o" + ((PlayerInfo*)(event.peer->data))->tankIDName + "`o just left game...")); + ENetPacket * packet = enet_packet_create(p.data, + p.len, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(currentPeer, 0, packet); + enet_host_flush(server); + }*/ + sendPlayerLeave(peer, (PlayerInfo*)(event.peer->data)); + ((PlayerInfo*)(event.peer->data))->inventory.items.clear(); + delete event.peer->data; + event.peer->data = NULL; + } + } + cout << "Program ended??? Huh?" << endl; + while (1); + return 0; +} + diff --git a/enet server test/enet server test.vcxproj b/enet server test/enet server test.vcxproj new file mode 100644 index 0000000..1f9adf3 --- /dev/null +++ b/enet server test/enet server test.vcxproj @@ -0,0 +1,177 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0F151D58-FD96-4DD5-A8D9-02A5F1D781D3} + Win32Proj + enetservertest + + + + Application + true + v140 + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);C:\Users\AMD\Documents\Visual Studio 2013\Projects\enet server test\enet server test\enet; + $(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Users\AMD\Documents\Visual Studio 2013\Projects\enet server test\enet server test\enet; + $(VC_ReferencesPath_x86);C:\Users\AMD\Documents\Visual Studio 2013\Projects\enet server test\enet server test\enet; + + + true + $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);C:\Users\AMD\Documents\Visual Studio 2013\Projects\enet server test\enet server test\enet; + $(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Users\AMD\Documents\Visual Studio 2013\Projects\enet server test\enet server test\enet; + $(VC_ReferencesPath_x86);C:\Users\AMD\Documents\Visual Studio 2013\Projects\enet server test\enet server test\enet; + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + enet.lib;ws2_32.lib;winmm.lib;%(AdditionalDependencies) + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + enet.lib;ws2_32.lib;winmm.lib;%(AdditionalDependencies) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + Speed + + + Console + true + true + true + enet.lib;ws2_32.lib;winmm.lib;%(AdditionalDependencies) + false + true + false + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + enet.lib;ws2_32.lib;winmm.lib;%(AdditionalDependencies) + false + true + false + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/enet server test/enet server test.vcxproj.filters b/enet server test/enet server test.vcxproj.filters new file mode 100644 index 0000000..a2f8be8 --- /dev/null +++ b/enet server test/enet server test.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/enet server test/enet.lib b/enet server test/enet.lib new file mode 100644 index 0000000..6ce8caa Binary files /dev/null and b/enet server test/enet.lib differ diff --git a/enet server test/enet/callbacks.h b/enet server test/enet/callbacks.h new file mode 100644 index 0000000..340a4a9 --- /dev/null +++ b/enet server test/enet/callbacks.h @@ -0,0 +1,27 @@ +/** + @file callbacks.h + @brief ENet callbacks +*/ +#ifndef __ENET_CALLBACKS_H__ +#define __ENET_CALLBACKS_H__ + +#include + +typedef struct _ENetCallbacks +{ + void * (ENET_CALLBACK * malloc) (size_t size); + void (ENET_CALLBACK * free) (void * memory); + void (ENET_CALLBACK * no_memory) (void); +} ENetCallbacks; + +/** @defgroup callbacks ENet internal callbacks + @{ + @ingroup private +*/ +extern void * enet_malloc (size_t); +extern void enet_free (void *); + +/** @} */ + +#endif /* __ENET_CALLBACKS_H__ */ + diff --git a/enet server test/enet/enet.h b/enet server test/enet/enet.h new file mode 100644 index 0000000..5e21ee8 --- /dev/null +++ b/enet server test/enet/enet.h @@ -0,0 +1,592 @@ +/** + @file enet.h + @brief ENet public header file +*/ +#ifndef __ENET_ENET_H__ +#define __ENET_ENET_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef _WIN32 +#include "enet/win32.h" +#else +#include "enet/unix.h" +#endif + +#include "enet/types.h" +#include "enet/protocol.h" +#include "enet/list.h" +#include "enet/callbacks.h" + +#define ENET_VERSION_MAJOR 1 +#define ENET_VERSION_MINOR 3 +#define ENET_VERSION_PATCH 13 +#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) +#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) +#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) +#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) +#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) + +typedef enet_uint32 ENetVersion; + +struct _ENetHost; +struct _ENetEvent; +struct _ENetPacket; + +typedef enum _ENetSocketType +{ + ENET_SOCKET_TYPE_STREAM = 1, + ENET_SOCKET_TYPE_DATAGRAM = 2 +} ENetSocketType; + +typedef enum _ENetSocketWait +{ + ENET_SOCKET_WAIT_NONE = 0, + ENET_SOCKET_WAIT_SEND = (1 << 0), + ENET_SOCKET_WAIT_RECEIVE = (1 << 1), + ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) +} ENetSocketWait; + +typedef enum _ENetSocketOption +{ + ENET_SOCKOPT_NONBLOCK = 1, + ENET_SOCKOPT_BROADCAST = 2, + ENET_SOCKOPT_RCVBUF = 3, + ENET_SOCKOPT_SNDBUF = 4, + ENET_SOCKOPT_REUSEADDR = 5, + ENET_SOCKOPT_RCVTIMEO = 6, + ENET_SOCKOPT_SNDTIMEO = 7, + ENET_SOCKOPT_ERROR = 8, + ENET_SOCKOPT_NODELAY = 9 +} ENetSocketOption; + +typedef enum _ENetSocketShutdown +{ + ENET_SOCKET_SHUTDOWN_READ = 0, + ENET_SOCKET_SHUTDOWN_WRITE = 1, + ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 +} ENetSocketShutdown; + +#define ENET_HOST_ANY 0 +#define ENET_HOST_BROADCAST 0xFFFFFFFFU +#define ENET_PORT_ANY 0 + +/** + * Portable internet address structure. + * + * The host must be specified in network byte-order, and the port must be in host + * byte-order. The constant ENET_HOST_ANY may be used to specify the default + * server host. The constant ENET_HOST_BROADCAST may be used to specify the + * broadcast address (255.255.255.255). This makes sense for enet_host_connect, + * but not for enet_host_create. Once a server responds to a broadcast, the + * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. + */ +typedef struct _ENetAddress +{ + enet_uint32 host; + enet_uint16 port; +} ENetAddress; + +/** + * Packet flag bit constants. + * + * The host must be specified in network byte-order, and the port must be in + * host byte-order. The constant ENET_HOST_ANY may be used to specify the + * default server host. + + @sa ENetPacket +*/ +typedef enum _ENetPacketFlag +{ + /** packet must be received by the target peer and resend attempts should be + * made until the packet is delivered */ + ENET_PACKET_FLAG_RELIABLE = (1 << 0), + /** packet will not be sequenced with other packets + * not supported for reliable packets + */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), + /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), + /** packet will be fragmented using unreliable (instead of reliable) sends + * if it exceeds the MTU */ + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), + + /** whether the packet has been sent from all queues it has been entered into */ + ENET_PACKET_FLAG_SENT = (1<<8) +} ENetPacketFlag; + +typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); + +/** + * ENet packet structure. + * + * An ENet data packet that may be sent to or received from a peer. The shown + * fields should only be read and never modified. The data field contains the + * allocated data for the packet. The dataLength fields specifies the length + * of the allocated data. The flags field is either 0 (specifying no flags), + * or a bitwise-or of any combination of the following flags: + * + * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer + * and resend attempts should be made until the packet is delivered + * + * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets + * (not supported for reliable packets) + * + * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead + + @sa ENetPacketFlag + */ +typedef struct _ENetPacket +{ + size_t referenceCount; /**< internal use only */ + enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ + enet_uint8 * data; /**< allocated data for packet */ + size_t dataLength; /**< length of data */ + ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ + void * userData; /**< application private data, may be freely modified */ +} ENetPacket; + +typedef struct _ENetAcknowledgement +{ + ENetListNode acknowledgementList; + enet_uint32 sentTime; + ENetProtocol command; +} ENetAcknowledgement; + +typedef struct _ENetOutgoingCommand +{ + ENetListNode outgoingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + enet_uint32 sentTime; + enet_uint32 roundTripTimeout; + enet_uint32 roundTripTimeoutLimit; + enet_uint32 fragmentOffset; + enet_uint16 fragmentLength; + enet_uint16 sendAttempts; + ENetProtocol command; + ENetPacket * packet; +} ENetOutgoingCommand; + +typedef struct _ENetIncomingCommand +{ + ENetListNode incomingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + ENetProtocol command; + enet_uint32 fragmentCount; + enet_uint32 fragmentsRemaining; + enet_uint32 * fragments; + ENetPacket * packet; +} ENetIncomingCommand; + +typedef enum _ENetPeerState +{ + ENET_PEER_STATE_DISCONNECTED = 0, + ENET_PEER_STATE_CONNECTING = 1, + ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, + ENET_PEER_STATE_CONNECTION_PENDING = 3, + ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, + ENET_PEER_STATE_CONNECTED = 5, + ENET_PEER_STATE_DISCONNECT_LATER = 6, + ENET_PEER_STATE_DISCONNECTING = 7, + ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, + ENET_PEER_STATE_ZOMBIE = 9 +} ENetPeerState; + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +enum +{ + ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, + ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, + ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, + ENET_HOST_DEFAULT_MTU = 1400, + ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, + ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024, + + ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, + ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, + ENET_PEER_PACKET_THROTTLE_SCALE = 32, + ENET_PEER_PACKET_THROTTLE_COUNTER = 7, + ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, + ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, + ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, + ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), + ENET_PEER_PACKET_LOSS_INTERVAL = 10000, + ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, + ENET_PEER_TIMEOUT_LIMIT = 32, + ENET_PEER_TIMEOUT_MINIMUM = 5000, + ENET_PEER_TIMEOUT_MAXIMUM = 30000, + ENET_PEER_PING_INTERVAL = 500, + ENET_PEER_UNSEQUENCED_WINDOWS = 64, + ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, + ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, + ENET_PEER_RELIABLE_WINDOWS = 16, + ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, + ENET_PEER_FREE_RELIABLE_WINDOWS = 8 +}; + +typedef struct _ENetChannel +{ + enet_uint16 outgoingReliableSequenceNumber; + enet_uint16 outgoingUnreliableSequenceNumber; + enet_uint16 usedReliableWindows; + enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; + enet_uint16 incomingReliableSequenceNumber; + enet_uint16 incomingUnreliableSequenceNumber; + ENetList incomingReliableCommands; + ENetList incomingUnreliableCommands; +} ENetChannel; + +/** + * An ENet peer which data packets may be sent or received from. + * + * No fields should be modified unless otherwise specified. + */ +typedef struct _ENetPeer +{ + ENetListNode dispatchList; + struct _ENetHost * host; + enet_uint16 outgoingPeerID; + enet_uint16 incomingPeerID; + enet_uint32 connectID; + enet_uint8 outgoingSessionID; + enet_uint8 incomingSessionID; + ENetAddress address; /**< Internet address of the peer */ + void * data; /**< Application private data, may be freely modified */ + ENetPeerState state; + ENetChannel * channels; + size_t channelCount; /**< Number of channels allocated for communication with peer */ + enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + enet_uint32 incomingBandwidthThrottleEpoch; + enet_uint32 outgoingBandwidthThrottleEpoch; + enet_uint32 incomingDataTotal; + enet_uint32 outgoingDataTotal; + enet_uint32 lastSendTime; + enet_uint32 lastReceiveTime; + enet_uint32 nextTimeout; + enet_uint32 earliestTimeout; + enet_uint32 packetLossEpoch; + enet_uint32 packetsSent; + enet_uint32 packetsLost; + enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + enet_uint32 packetLossVariance; + enet_uint32 packetThrottle; + enet_uint32 packetThrottleLimit; + enet_uint32 packetThrottleCounter; + enet_uint32 packetThrottleEpoch; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 packetThrottleInterval; + enet_uint32 pingInterval; + enet_uint32 timeoutLimit; + enet_uint32 timeoutMinimum; + enet_uint32 timeoutMaximum; + enet_uint32 lastRoundTripTime; + enet_uint32 lowestRoundTripTime; + enet_uint32 lastRoundTripTimeVariance; + enet_uint32 highestRoundTripTimeVariance; + enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ + enet_uint32 roundTripTimeVariance; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 reliableDataInTransit; + enet_uint16 outgoingReliableSequenceNumber; + ENetList acknowledgements; + ENetList sentReliableCommands; + ENetList sentUnreliableCommands; + ENetList outgoingReliableCommands; + ENetList outgoingUnreliableCommands; + ENetList dispatchedCommands; + int needsDispatch; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; + enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 eventData; + size_t totalWaitingData; +} ENetPeer; + +/** An ENet packet compressor for compressing UDP packets before socket sends or receives. + */ +typedef struct _ENetCompressor +{ + /** Context data for the compressor. Must be non-NULL. */ + void * context; + /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ + void (ENET_CALLBACK * destroy) (void * context); +} ENetCompressor; + +/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ +typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); + +/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ +typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event); + +/** An ENet host for communicating with peers. + * + * No fields should be modified unless otherwise stated. + + @sa enet_host_create() + @sa enet_host_destroy() + @sa enet_host_connect() + @sa enet_host_service() + @sa enet_host_flush() + @sa enet_host_broadcast() + @sa enet_host_compress() + @sa enet_host_compress_with_range_coder() + @sa enet_host_channel_limit() + @sa enet_host_bandwidth_limit() + @sa enet_host_bandwidth_throttle() + */ +typedef struct _ENetHost +{ + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + enet_uint32 randomSeed; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + size_t channelLimit; /**< maximum number of channels allowed for connected peers */ + enet_uint32 serviceTime; + ENetList dispatchQueue; + int continueSending; + size_t packetSize; + enet_uint16 headerFlags; + ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; + size_t commandCount; + ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; + size_t bufferCount; + ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ + ENetCompressor compressor; + enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; + ENetAddress receivedAddress; + enet_uint8 * receivedData; + size_t receivedDataLength; + enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ + ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ + size_t connectedPeers; + size_t bandwidthLimitedPeers; + size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ + size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */ + size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */ +} ENetHost; + +/** + * An ENet event type, as specified in @ref ENetEvent. + */ +typedef enum _ENetEventType +{ + /** no event occurred within the specified time limit */ + ENET_EVENT_TYPE_NONE = 0, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + ENET_EVENT_TYPE_CONNECT = 1, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_pper_disconnect, if + * a peer has timed out, or if a connection request intialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + ENET_EVENT_TYPE_DISCONNECT = 2, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + ENET_EVENT_TYPE_RECEIVE = 3 +} ENetEventType; + +/** + * An ENet event as returned by enet_host_service(). + + @sa enet_host_service + */ +typedef struct _ENetEvent +{ + ENetEventType type; /**< type of the event */ + ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ + enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ + enet_uint32 data; /**< data associated with the event, if appropriate */ + ENetPacket * packet; /**< packet associated with the event, if appropriate */ +} ENetEvent; + +/** @defgroup global ENet global functions + @{ +*/ + +/** + Initializes ENet globally. Must be called prior to using any functions in + ENet. + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize (void); + +/** + Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. + + @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use + @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); + +/** + Shuts down ENet globally. Should be called when a program that has + initialized ENet exits. +*/ +ENET_API void enet_deinitialize (void); + +/** + Gives the linked version of the ENet library. + @returns the version number +*/ +ENET_API ENetVersion enet_linked_version (void); + +/** @} */ + +/** @defgroup private ENet private implementation functions */ + +/** + Returns the wall-time in milliseconds. Its initial value is unspecified + unless otherwise set. + */ +ENET_API enet_uint32 enet_time_get (void); +/** + Sets the current wall-time in milliseconds. + */ +ENET_API void enet_time_set (enet_uint32); + +/** @defgroup socket ENet socket functions + @{ +*/ +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *); +ENET_API int enet_socket_listen (ENetSocket, int); +ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); +ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *); +ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown); +ENET_API void enet_socket_destroy (ENetSocket); +ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); + +/** @} */ + +/** @defgroup Address ENet address functions + @{ +*/ +/** Attempts to resolve the host named by the parameter hostName and sets + the host field in the address parameter if successful. + @param address destination to store resolved address + @param hostName host name to lookup + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); + +/** Gives the printable form of the IP address specified in the address parameter. + @param address address printed + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); + +/** Attempts to do a reverse lookup of the host field in the address parameter. + @param address address used for reverse lookup + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); + +/** @} */ + +ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); +ENET_API void enet_packet_destroy (ENetPacket *); +ENET_API int enet_packet_resize (ENetPacket *, size_t); +ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t); + +ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); +ENET_API void enet_host_destroy (ENetHost *); +ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); +ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); +ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); +ENET_API void enet_host_flush (ENetHost *); +ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); +ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); +ENET_API int enet_host_compress_with_range_coder (ENetHost * host); +ENET_API void enet_host_channel_limit (ENetHost *, size_t); +ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); +extern void enet_host_bandwidth_throttle (ENetHost *); +extern enet_uint32 enet_host_random_seed (void); + +ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); +ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); +ENET_API void enet_peer_ping (ENetPeer *); +ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32); +ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +ENET_API void enet_peer_reset (ENetPeer *); +ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); +ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +extern int enet_peer_throttle (ENetPeer *, enet_uint32); +extern void enet_peer_reset_queues (ENetPeer *); +extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); +extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); +extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); +extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); +extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_on_connect (ENetPeer *); +extern void enet_peer_on_disconnect (ENetPeer *); + +ENET_API void * enet_range_coder_create (void); +ENET_API void enet_range_coder_destroy (void *); +ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); +ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#endif /* __ENET_ENET_H__ */ + diff --git a/enet server test/enet/list.h b/enet server test/enet/list.h new file mode 100644 index 0000000..d7b2600 --- /dev/null +++ b/enet server test/enet/list.h @@ -0,0 +1,43 @@ +/** + @file list.h + @brief ENet list management +*/ +#ifndef __ENET_LIST_H__ +#define __ENET_LIST_H__ + +#include + +typedef struct _ENetListNode +{ + struct _ENetListNode * next; + struct _ENetListNode * previous; +} ENetListNode; + +typedef ENetListNode * ENetListIterator; + +typedef struct _ENetList +{ + ENetListNode sentinel; +} ENetList; + +extern void enet_list_clear (ENetList *); + +extern ENetListIterator enet_list_insert (ENetListIterator, void *); +extern void * enet_list_remove (ENetListIterator); +extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); + +extern size_t enet_list_size (ENetList *); + +#define enet_list_begin(list) ((list) -> sentinel.next) +#define enet_list_end(list) (& (list) -> sentinel) + +#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) + +#define enet_list_next(iterator) ((iterator) -> next) +#define enet_list_previous(iterator) ((iterator) -> previous) + +#define enet_list_front(list) ((void *) (list) -> sentinel.next) +#define enet_list_back(list) ((void *) (list) -> sentinel.previous) + +#endif /* __ENET_LIST_H__ */ + diff --git a/enet server test/enet/protocol.h b/enet server test/enet/protocol.h new file mode 100644 index 0000000..f8c73d8 --- /dev/null +++ b/enet server test/enet/protocol.h @@ -0,0 +1,198 @@ +/** + @file protocol.h + @brief ENet protocol +*/ +#ifndef __ENET_PROTOCOL_H__ +#define __ENET_PROTOCOL_H__ + +#include "enet/types.h" + +enum +{ + ENET_PROTOCOL_MINIMUM_MTU = 576, + ENET_PROTOCOL_MAXIMUM_MTU = 4096, + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, + ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 +}; + +typedef enum _ENetProtocolCommand +{ + ENET_PROTOCOL_COMMAND_NONE = 0, + ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, + ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, + ENET_PROTOCOL_COMMAND_COUNT = 13, + + ENET_PROTOCOL_COMMAND_MASK = 0x0F +} ENetProtocolCommand; + +typedef enum _ENetProtocolFlag +{ + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), + + ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, + + ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 +} ENetProtocolFlag; + +#ifdef _MSC_VER +#pragma pack(push, 1) +#define ENET_PACKED +#elif defined(__GNUC__) || defined(__clang__) +#define ENET_PACKED __attribute__ ((packed)) +#else +#define ENET_PACKED +#endif + +typedef struct _ENetProtocolHeader +{ + enet_uint16 peerID; + enet_uint16 sentTime; +} ENET_PACKED ENetProtocolHeader; + +typedef struct _ENetProtocolCommandHeader +{ + enet_uint8 command; + enet_uint8 channelID; + enet_uint16 reliableSequenceNumber; +} ENET_PACKED ENetProtocolCommandHeader; + +typedef struct _ENetProtocolAcknowledge +{ + ENetProtocolCommandHeader header; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENET_PACKED ENetProtocolAcknowledge; + +typedef struct _ENetProtocolConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; + enet_uint32 data; +} ENET_PACKED ENetProtocolConnect; + +typedef struct _ENetProtocolVerifyConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; +} ENET_PACKED ENetProtocolVerifyConnect; + +typedef struct _ENetProtocolBandwidthLimit +{ + ENetProtocolCommandHeader header; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; +} ENET_PACKED ENetProtocolBandwidthLimit; + +typedef struct _ENetProtocolThrottleConfigure +{ + ENetProtocolCommandHeader header; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENET_PACKED ENetProtocolThrottleConfigure; + +typedef struct _ENetProtocolDisconnect +{ + ENetProtocolCommandHeader header; + enet_uint32 data; +} ENET_PACKED ENetProtocolDisconnect; + +typedef struct _ENetProtocolPing +{ + ENetProtocolCommandHeader header; +} ENET_PACKED ENetProtocolPing; + +typedef struct _ENetProtocolSendReliable +{ + ENetProtocolCommandHeader header; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendReliable; + +typedef struct _ENetProtocolSendUnreliable +{ + ENetProtocolCommandHeader header; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnreliable; + +typedef struct _ENetProtocolSendUnsequenced +{ + ENetProtocolCommandHeader header; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnsequenced; + +typedef struct _ENetProtocolSendFragment +{ + ENetProtocolCommandHeader header; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; + enet_uint32 fragmentCount; + enet_uint32 fragmentNumber; + enet_uint32 totalLength; + enet_uint32 fragmentOffset; +} ENET_PACKED ENetProtocolSendFragment; + +typedef union _ENetProtocol +{ + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolConnect connect; + ENetProtocolVerifyConnect verifyConnect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolThrottleConfigure throttleConfigure; +} ENET_PACKED ENetProtocol; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +#endif /* __ENET_PROTOCOL_H__ */ + diff --git a/enet server test/enet/time.h b/enet server test/enet/time.h new file mode 100644 index 0000000..c82a546 --- /dev/null +++ b/enet server test/enet/time.h @@ -0,0 +1,18 @@ +/** + @file time.h + @brief ENet time constants and macros +*/ +#ifndef __ENET_TIME_H__ +#define __ENET_TIME_H__ + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +#endif /* __ENET_TIME_H__ */ + diff --git a/enet server test/enet/types.h b/enet server test/enet/types.h new file mode 100644 index 0000000..ab010a4 --- /dev/null +++ b/enet server test/enet/types.h @@ -0,0 +1,13 @@ +/** + @file types.h + @brief type definitions for ENet +*/ +#ifndef __ENET_TYPES_H__ +#define __ENET_TYPES_H__ + +typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ +typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ +typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ + +#endif /* __ENET_TYPES_H__ */ + diff --git a/enet server test/enet/unix.h b/enet server test/enet/unix.h new file mode 100644 index 0000000..a59e340 --- /dev/null +++ b/enet server test/enet/unix.h @@ -0,0 +1,47 @@ +/** + @file unix.h + @brief ENet Unix header +*/ +#ifndef __ENET_UNIX_H__ +#define __ENET_UNIX_H__ + +#include +#include +#include +#include +#include +#include + +#ifdef MSG_MAXIOVLEN +#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN +#endif + +typedef int ENetSocket; + +#define ENET_SOCKET_NULL -1 + +#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ +#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ + +typedef struct +{ + void * data; + size_t dataLength; +} ENetBuffer; + +#define ENET_CALLBACK + +#define ENET_API extern + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_UNIX_H__ */ + diff --git a/enet server test/enet/utility.h b/enet server test/enet/utility.h new file mode 100644 index 0000000..e48a476 --- /dev/null +++ b/enet server test/enet/utility.h @@ -0,0 +1,12 @@ +/** + @file utility.h + @brief ENet utility header +*/ +#ifndef __ENET_UTILITY_H__ +#define __ENET_UTILITY_H__ + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#endif /* __ENET_UTILITY_H__ */ + diff --git a/enet server test/enet/win32.h b/enet server test/enet/win32.h new file mode 100644 index 0000000..e73ca9d --- /dev/null +++ b/enet server test/enet/win32.h @@ -0,0 +1,57 @@ +/** + @file win32.h + @brief ENet Win32 header +*/ +#ifndef __ENET_WIN32_H__ +#define __ENET_WIN32_H__ + +#ifdef _MSC_VER +#ifdef ENET_BUILDING_LIB +#pragma warning (disable: 4267) // size_t to int conversion +#pragma warning (disable: 4244) // 64bit to 32bit int +#pragma warning (disable: 4018) // signed/unsigned mismatch +#pragma warning (disable: 4146) // unary minus operator applied to unsigned type +#endif +#endif + +#include +#include + +typedef SOCKET ENetSocket; + +#define ENET_SOCKET_NULL INVALID_SOCKET + +#define ENET_HOST_TO_NET_16(value) (htons (value)) +#define ENET_HOST_TO_NET_32(value) (htonl (value)) + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) + +typedef struct +{ + size_t dataLength; + void * data; +} ENetBuffer; + +#define ENET_CALLBACK __cdecl + +#ifdef ENET_DLL +#ifdef ENET_BUILDING_LIB +#define ENET_API __declspec( dllexport ) +#else +#define ENET_API __declspec( dllimport ) +#endif /* ENET_BUILDING_LIB */ +#else /* !ENET_DLL */ +#define ENET_API extern +#endif /* ENET_DLL */ + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_WIN32_H__ */ + + diff --git a/enet server test/enet2/CMakeLists.txt b/enet server test/enet2/CMakeLists.txt new file mode 100644 index 0000000..ce6dc8f --- /dev/null +++ b/enet server test/enet2/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 2.6) + +project(enet) + +# The "configure" step. +include(CheckFunctionExists) +include(CheckStructHasMember) +include(CheckTypeSize) +check_function_exists("fcntl" HAS_FCNTL) +check_function_exists("poll" HAS_POLL) +check_function_exists("gethostbyname_r" HAS_GETHOSTBYNAME_R) +check_function_exists("gethostbyaddr_r" HAS_GETHOSTBYADDR_R) +check_function_exists("inet_pton" HAS_INET_PTON) +check_function_exists("inet_ntop" HAS_INET_NTOP) +check_struct_has_member("struct msghdr" "msg_flags" "sys/types.h;sys/socket.h" HAS_MSGHDR_FLAGS) +set(CMAKE_EXTRA_INCLUDE_FILES "sys/types.h" "sys/socket.h") +check_type_size("socklen_t" HAS_SOCKLEN_T BUILTIN_TYPES_ONLY) +unset(CMAKE_EXTRA_INCLUDE_FILES) + +if(HAS_FCNTL) + add_definitions(-DHAS_FCNTL=1) +endif() +if(HAS_POLL) + add_definitions(-DHAS_POLL=1) +endif() +if(HAS_GETHOSTBYNAME_R) + add_definitions(-DHAS_GETHOSTBYNAME_R=1) +endif() +if(HAS_GETHOSTBYADDR_R) + add_definitions(-DHAS_GETHOSTBYADDR_R=1) +endif() +if(HAS_INET_PTON) + add_definitions(-DHAS_INET_PTON=1) +endif() +if(HAS_INET_NTOP) + add_definitions(-DHAS_INET_NTOP=1) +endif() +if(HAS_MSGHDR_FLAGS) + add_definitions(-DHAS_MSGHDR_FLAGS=1) +endif() +if(HAS_SOCKLEN_T) + add_definitions(-DHAS_SOCKLEN_T=1) +endif() + +include_directories(${PROJECT_SOURCE_DIR}/include) + +add_library(enet STATIC + callbacks.c + compress.c + host.c + list.c + packet.c + peer.c + protocol.c + unix.c + win32.c + ) diff --git a/enet server test/enet2/ChangeLog b/enet server test/enet2/ChangeLog new file mode 100644 index 0000000..9386a01 --- /dev/null +++ b/enet server test/enet2/ChangeLog @@ -0,0 +1,177 @@ +ENet 1.3.13 (April 30, 2015): + +* miscellaneous bug fixes +* added premake and cmake support +* miscellaneous documentation cleanups + +ENet 1.3.12 (April 24, 2014): + +* added maximumPacketSize and maximumWaitingData fields to ENetHost to limit the amount of +data waiting to be delivered on a peer (beware that the default maximumPacketSize is +32MB and should be set higher if desired as should maximumWaitingData) + +ENet 1.3.11 (December 26, 2013): + +* allow an ENetHost to connect to itself +* fixed possible bug with disconnect notifications during connect attempts +* fixed some preprocessor definition bugs + +ENet 1.3.10 (October 23, 2013); + +* doubled maximum reliable window size +* fixed RCVTIMEO/SNDTIMEO socket options and also added NODELAY + +ENet 1.3.9 (August 19, 2013): + +* added duplicatePeers option to ENetHost which can limit the number of peers from duplicate IPs +* added enet_socket_get_option() and ENET_SOCKOPT_ERROR +* added enet_host_random_seed() platform stub + +ENet 1.3.8 (June 2, 2013): + +* added enet_linked_version() for checking the linked version +* added enet_socket_get_address() for querying the local address of a socket +* silenced some debugging prints unless ENET_DEBUG is defined during compilation +* handle EINTR in enet_socket_wait() so that enet_host_service() doesn't propagate errors from signals +* optimized enet_host_bandwidth_throttle() to be less expensive for large numbers of peers + +ENet 1.3.7 (March 6, 2013): + +* added ENET_PACKET_FLAG_SENT to indicate that a packet is being freed because it has been sent +* added userData field to ENetPacket +* changed how random seed is generated on Windows to avoid import warnings +* fixed case where disconnects could be generated with no preceding connect event + +ENet 1.3.6 (December 11, 2012): + +* added support for intercept callback in ENetHost that can be used to process raw packets before ENet +* added enet_socket_shutdown() for issuing shutdown on a socket +* fixed enet_socket_connect() to not error on non-blocking connects +* fixed bug in MTU negotiation during connections + +ENet 1.3.5 (July 31, 2012): + +* fixed bug in unreliable packet fragment queuing + +ENet 1.3.4 (May 29, 2012): + +* added enet_peer_ping_interval() for configuring per-peer ping intervals +* added enet_peer_timeout() for configuring per-peer timeouts +* added protocol packet size limits + +ENet 1.3.3 (June 28, 2011): + +* fixed bug with simultaneous disconnects not dispatching events + +ENet 1.3.2 (May 31, 2011): + +* added support for unreliable packet fragmenting via the packet flag +ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT +* fixed regression in unreliable packet queuing +* added check against received port to limit some forms of IP-spoofing + +ENet 1.3.1 (February 10, 2011): + +* fixed bug in tracking of reliable data in transit +* reliable data window size now scales with the throttle +* fixed bug in fragment length calculation when checksums are used + +ENet 1.3.0 (June 5, 2010): + +* enet_host_create() now requires the channel limit to be specified as +a parameter +* enet_host_connect() now accepts a data parameter which is supplied +to the receiving receiving host in the event data field for a connect event +* added an adaptive order-2 PPM range coder as a built-in compressor option +which can be set with enet_host_compress_with_range_coder() +* added support for packet compression configurable with a callback +* improved session number handling to not rely on the packet checksum +field, saving 4 bytes per packet unless the checksum option is used +* removed the dependence on the rand callback for session number handling + +Caveats: This version is not protocol compatible with the 1.2 series or +earlier. The enet_host_connect and enet_host_create API functions require +supplying additional parameters. + +ENet 1.2.5 (June 28, 2011): + +* fixed bug with simultaneous disconnects not dispatching events + +ENet 1.2.4 (May 31, 2011): + +* fixed regression in unreliable packet queuing +* added check against received port to limit some forms of IP-spoofing + +ENet 1.2.3 (February 10, 2011): + +* fixed bug in tracking reliable data in transit + +ENet 1.2.2 (June 5, 2010): + +* checksum functionality is now enabled by setting a checksum callback +inside ENetHost instead of being a configure script option +* added totalSentData, totalSentPackets, totalReceivedData, and +totalReceivedPackets counters inside ENetHost for getting usage +statistics +* added enet_host_channel_limit() for limiting the maximum number of +channels allowed by connected peers +* now uses dispatch queues for event dispatch rather than potentially +unscalable array walking +* added no_memory callback that is called when a malloc attempt fails, +such that if no_memory returns rather than aborts (the default behavior), +then the error is propagated to the return value of the API calls +* now uses packed attribute for protocol structures on platforms with +strange alignment rules +* improved autoconf build system contributed by Nathan Brink allowing +for easier building as a shared library + +Caveats: If you were using the compile-time option that enabled checksums, +make sure to set the checksum callback inside ENetHost to enet_crc32 to +regain the old behavior. The ENetCallbacks structure has added new fields, +so make sure to clear the structure to zero before use if +using enet_initialize_with_callbacks(). + +ENet 1.2.1 (November 12, 2009): + +* fixed bug that could cause disconnect events to be dropped +* added thin wrapper around select() for portable usage +* added ENET_SOCKOPT_REUSEADDR socket option +* factored enet_socket_bind()/enet_socket_listen() out of enet_socket_create() +* added contributed Code::Blocks build file + +ENet 1.2 (February 12, 2008): + +* fixed bug in VERIFY_CONNECT acknowledgement that could cause connect +attempts to occasionally timeout +* fixed acknowledgements to check both the outgoing and sent queues +when removing acknowledged packets +* fixed accidental bit rot in the MSVC project file +* revised sequence number overflow handling to address some possible +disconnect bugs +* added enet_host_check_events() for getting only local queued events +* factored out socket option setting into enet_socket_set_option() so +that socket options are now set separately from enet_socket_create() + +Caveats: While this release is superficially protocol compatible with 1.1, +differences in the sequence number overflow handling can potentially cause +random disconnects. + +ENet 1.1 (June 6, 2007): + +* optional CRC32 just in case someone needs a stronger checksum than UDP +provides (--enable-crc32 configure option) +* the size of packet headers are half the size they used to be (so less +overhead when sending small packets) +* enet_peer_disconnect_later() that waits till all queued outgoing +packets get sent before issuing an actual disconnect +* freeCallback field in individual packets for notification of when a +packet is about to be freed +* ENET_PACKET_FLAG_NO_ALLOCATE for supplying pre-allocated data to a +packet (can be used in concert with freeCallback to support some custom +allocation schemes that the normal memory allocation callbacks would +normally not allow) +* enet_address_get_host_ip() for printing address numbers +* promoted the enet_socket_*() functions to be part of the API now +* a few stability/crash fixes + + diff --git a/enet server test/enet2/Doxyfile b/enet server test/enet2/Doxyfile new file mode 100644 index 0000000..597ef1a --- /dev/null +++ b/enet server test/enet2/Doxyfile @@ -0,0 +1,2303 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "ENet" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = v1.3.13 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Reliable UDP networking library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = YES + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = YES + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = YES + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = YES + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = YES + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = DoxygenLayout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c *.h *.dox + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = ${CMAKE_CURRENT_SOURCE_DIR} + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = NO + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 1 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 118 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 240 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 0 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 1 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /