├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── LICENSE.MD ├── README.MD ├── RetroSpy.SQL ├── RetroSpy.db ├── common ├── CMakeLists.txt ├── Defines.h ├── Helper.cpp ├── Helper.h ├── Helper_Base64.cpp ├── Helper_Query.cpp ├── Helper_Random.cpp ├── TemplateStringServer.cpp ├── TemplateStringServer.h ├── chc_endian.cpp ├── chc_endian.h ├── md5.c └── md5.h ├── natneg ├── CMakeLists.txt ├── Client.cpp ├── Client.h ├── ClientManager.cpp ├── ClientManager.h ├── NNServer.cpp ├── NNServer.h └── NNTypes.h ├── peerchat ├── CMakeLists.txt ├── Cache.cpp ├── Cache.h ├── IRCChannel.cpp ├── IRCChannel.h ├── IRCClient.cpp ├── IRCClient.h ├── PeerChatServer.cpp ├── PeerChatServer.h └── Structs.h ├── playersearch ├── CMakeLists.txt ├── PSServer.cpp └── PSServer.h ├── playerspy ├── CMakeLists.txt ├── Client.cpp ├── Client.h ├── ClientManager.cpp ├── ClientManager.h ├── PYServer.cpp ├── PYServer.h └── Types.h └── queryreport2 ├── CMakeLists.txt ├── QR2Server.cpp └── QR2Server.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | ## Ignore Visual Studio temporary files, build results, and 35 | ## files generated by popular Visual Studio add-ons. 36 | ## 37 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.userosscache 43 | *.sln.docstates 44 | 45 | # User-specific files (MonoDevelop/Xamarin Studio) 46 | *.userprefs 47 | 48 | # Build results 49 | [Dd]ebug/ 50 | [Dd]ebugPublic/ 51 | [Rr]elease/ 52 | [Rr]eleases/ 53 | x64/ 54 | x86/ 55 | bld/ 56 | [Bb]in/ 57 | [Oo]bj/ 58 | [Ll]og/ 59 | 60 | # Visual Studio 2015/2017 cache/options directory 61 | .vs/ 62 | # Uncomment if you have tasks that create the project's static files in wwwroot 63 | #wwwroot/ 64 | 65 | # Visual Studio 2017 auto generated files 66 | Generated\ Files/ 67 | 68 | # MSTest test Results 69 | [Tt]est[Rr]esult*/ 70 | [Bb]uild[Ll]og.* 71 | 72 | # NUNIT 73 | *.VisualState.xml 74 | TestResult.xml 75 | 76 | # Build Results of an ATL Project 77 | [Dd]ebugPS/ 78 | [Rr]eleasePS/ 79 | dlldata.c 80 | 81 | # Benchmark Results 82 | BenchmarkDotNet.Artifacts/ 83 | 84 | # .NET Core 85 | project.lock.json 86 | project.fragment.lock.json 87 | artifacts/ 88 | **/Properties/launchSettings.json 89 | 90 | # StyleCop 91 | StyleCopReport.xml 92 | 93 | # Files built by Visual Studio 94 | *_i.c 95 | *_p.c 96 | *_i.h 97 | *.ilk 98 | *.meta 99 | *.obj 100 | *.pch 101 | *.pdb 102 | *.pgc 103 | *.pgd 104 | *.rsp 105 | *.sbr 106 | *.tlb 107 | *.tli 108 | *.tlh 109 | *.tmp 110 | *.tmp_proj 111 | *.log 112 | *.vspscc 113 | *.vssscc 114 | .builds 115 | *.pidb 116 | *.svclog 117 | *.scc 118 | 119 | # Chutzpah Test files 120 | _Chutzpah* 121 | 122 | # Visual C++ cache files 123 | ipch/ 124 | *.aps 125 | *.ncb 126 | *.opendb 127 | *.opensdf 128 | *.sdf 129 | *.cachefile 130 | *.VC.db 131 | *.VC.VC.opendb 132 | 133 | # Visual Studio profiler 134 | *.psess 135 | *.vsp 136 | *.vspx 137 | *.sap 138 | 139 | # Visual Studio Trace Files 140 | *.e2e 141 | 142 | # TFS 2012 Local Workspace 143 | $tf/ 144 | 145 | # Guidance Automation Toolkit 146 | *.gpState 147 | 148 | # ReSharper is a .NET coding add-in 149 | _ReSharper*/ 150 | *.[Rr]e[Ss]harper 151 | *.DotSettings.user 152 | 153 | # JustCode is a .NET coding add-in 154 | .JustCode 155 | 156 | # TeamCity is a build add-in 157 | _TeamCity* 158 | 159 | # DotCover is a Code Coverage Tool 160 | *.dotCover 161 | 162 | # AxoCover is a Code Coverage Tool 163 | .axoCover/* 164 | !.axoCover/settings.json 165 | 166 | # Visual Studio code coverage results 167 | *.coverage 168 | *.coveragexml 169 | 170 | # NCrunch 171 | _NCrunch_* 172 | .*crunch*.local.xml 173 | nCrunchTemp_* 174 | 175 | # MightyMoose 176 | *.mm.* 177 | AutoTest.Net/ 178 | 179 | # Web workbench (sass) 180 | .sass-cache/ 181 | 182 | # Installshield output folder 183 | [Ee]xpress/ 184 | 185 | # DocProject is a documentation generator add-in 186 | DocProject/buildhelp/ 187 | DocProject/Help/*.HxT 188 | DocProject/Help/*.HxC 189 | DocProject/Help/*.hhc 190 | DocProject/Help/*.hhk 191 | DocProject/Help/*.hhp 192 | DocProject/Help/Html2 193 | DocProject/Help/html 194 | 195 | # Click-Once directory 196 | publish/ 197 | 198 | # Publish Web Output 199 | *.[Pp]ublish.xml 200 | *.azurePubxml 201 | # Note: Comment the next line if you want to checkin your web deploy settings, 202 | # but database connection strings (with potential passwords) will be unencrypted 203 | *.pubxml 204 | *.publishproj 205 | 206 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 207 | # checkin your Azure Web App publish settings, but sensitive information contained 208 | # in these scripts will be unencrypted 209 | PublishScripts/ 210 | 211 | # NuGet Packages 212 | *.nupkg 213 | # The packages folder can be ignored because of Package Restore 214 | **/[Pp]ackages/* 215 | # except build/, which is used as an MSBuild target. 216 | !**/[Pp]ackages/build/ 217 | # Uncomment if necessary however generally it will be regenerated when needed 218 | #!**/[Pp]ackages/repositories.config 219 | # NuGet v3's project.json files produces more ignorable files 220 | *.nuget.props 221 | *.nuget.targets 222 | 223 | # Microsoft Azure Build Output 224 | csx/ 225 | *.build.csdef 226 | 227 | # Microsoft Azure Emulator 228 | ecf/ 229 | rcf/ 230 | 231 | # Windows Store app package directories and files 232 | AppPackages/ 233 | BundleArtifacts/ 234 | Package.StoreAssociation.xml 235 | _pkginfo.txt 236 | *.appx 237 | 238 | # Visual Studio cache files 239 | # files ending in .cache can be ignored 240 | *.[Cc]ache 241 | # but keep track of directories ending in .cache 242 | !*.[Cc]ache/ 243 | 244 | # Others 245 | ClientBin/ 246 | ~$* 247 | *~ 248 | *.dbmdl 249 | *.dbproj.schemaview 250 | *.jfm 251 | *.pfx 252 | *.publishsettings 253 | orleans.codegen.cs 254 | 255 | # Since there are multiple workflows, uncomment next line to ignore bower_components 256 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 257 | #bower_components/ 258 | 259 | # RIA/Silverlight projects 260 | Generated_Code/ 261 | 262 | # Backup & report files from converting an old project file 263 | # to a newer Visual Studio version. Backup files are not needed, 264 | # because we have git ;-) 265 | _UpgradeReport_Files/ 266 | Backup*/ 267 | UpgradeLog*.XML 268 | UpgradeLog*.htm 269 | 270 | # SQL Server files 271 | *.mdf 272 | *.ldf 273 | *.ndf 274 | 275 | # Business Intelligence projects 276 | *.rdl.data 277 | *.bim.layout 278 | *.bim_*.settings 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # TypeScript v1 declaration files 291 | typings/ 292 | 293 | # Visual Studio 6 build log 294 | *.plg 295 | 296 | # Visual Studio 6 workspace options file 297 | *.opt 298 | 299 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 300 | *.vbw 301 | 302 | # Visual Studio LightSwitch build output 303 | **/*.HTMLClient/GeneratedArtifacts 304 | **/*.DesktopClient/GeneratedArtifacts 305 | **/*.DesktopClient/ModelManifest.xml 306 | **/*.Server/GeneratedArtifacts 307 | **/*.Server/ModelManifest.xml 308 | _Pvt_Extensions 309 | 310 | # Paket dependency manager 311 | .paket/paket.exe 312 | paket-files/ 313 | 314 | # FAKE - F# Make 315 | .fake/ 316 | 317 | # JetBrains Rider 318 | .idea/ 319 | *.sln.iml 320 | 321 | # CodeRush 322 | .cr/ 323 | 324 | # Python Tools for Visual Studio (PTVS) 325 | __pycache__/ 326 | *.pyc 327 | 328 | # Cake - Uncomment if you are using it 329 | # tools/** 330 | # !tools/packages.config 331 | 332 | # Tabs Studio 333 | *.tss 334 | 335 | # Telerik's JustMock configuration file 336 | *.jmconfig 337 | 338 | # BizTalk build output 339 | *.btp.cs 340 | *.btm.cs 341 | *.odx.cs 342 | *.xsd.cs 343 | 344 | # OpenCover UI analysis results 345 | OpenCover/ 346 | 347 | # Azure Stream Analytics local run output 348 | ASALocalRun/ 349 | 350 | *.idb 351 | 352 | # SQLite database 353 | RetroSpySqlite3.db 354 | 355 | # Vs2008 projects 356 | [Dd]ebug_VS2008 357 | [Rr]elease_VS2008 358 | 359 | # MySQL specific 360 | VERSION.dep 361 | errmsg.sys 362 | libmysql_exports.def 363 | libmysql_dummy.c 364 | api_test.c 365 | sql_state.h 366 | mysqld_error.h 367 | mysqld_errname.h 368 | info_macros.cmake 369 | mysql_version.h 370 | config.h 371 | my_config.h 372 | INFO_SRC 373 | CPackConfig.cmake 374 | CPackSourceConfig.cmake 375 | mysqlclient_depends.c 376 | versioninfo_dll.rc 377 | versioninfo_exe.rc 378 | mysqld_ername.h 379 | INFO_BIN 380 | *-serverlog.txt 381 | *-servertrace.txt 382 | RetroSpy.ini 383 | build_* 384 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project("RetroSpyServer") 3 | 4 | # Add definitions for w32 build that dosen't support _WIN32 macro 5 | if (WIN32) 6 | add_definitions("-DWIN32 -D__WIN32__ -D_CRT_SECURE_NO_WARNINGS") 7 | endif() 8 | 9 | # Set -fPIC to allow compiling retrospy shared library with libuv 10 | if (NOT WIN32) 11 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") 13 | endif() 14 | 15 | # Set CMake output directory 16 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 17 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 18 | 19 | # RetroSpy projects 20 | add_subdirectory("common") 21 | add_subdirectory("playersearch") 22 | add_subdirectory("playerspy") 23 | add_subdirectory("queryreport2") 24 | add_subdirectory("natneg") 25 | add_subdirectory("peerchat") 26 | -------------------------------------------------------------------------------- /LICENSE.MD: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # RetroSpy Server 2 | 3 | RetroSpy is a GameSpy Project that aims to create GameSpy 2011/2012 services. 4 | 5 | The server is written in C++ and could be considered as the spiritual successor to OpenSpy Core since most of the modules are based from it. 6 | 7 | See the [wiki](https://github.com/GameProgressive/RetroSpyServer/wiki) for more information about compiling and creating a RetroSpy Server. 8 | 9 | ### Cloning submodules 10 | ``` 11 | git submodule init 12 | cd libuv-cmake 13 | git submodule init 14 | cd ../mysql-connector-cpp 15 | git submodule init 16 | cd .. 17 | git submodule update --recursive --remote 18 | ``` 19 | 20 | ### Special thanks 21 | * [Luigi Auriemma](http://aluigi.altervista.org/papers.htm) for his papers about gamespy that was used as a reference 22 | * [OpenSpy](https://github.com/Masaq-/Openspy-Core) for the architecture and the portions of code of the modules 23 | * [MySQL](https://www.mysql.com/) for their database server and C++ connector used in RetroSpy 24 | * [libUV](http://libuv.org/) for their awesome asyncrous I/O library that is used on the Server 25 | -------------------------------------------------------------------------------- /RetroSpy.SQL: -------------------------------------------------------------------------------- 1 | -- -------------------------------------------------------- 2 | -- Host: 127.0.0.1 3 | -- Versione server: 10.2.14-MariaDB - mariadb.org binary distribution 4 | -- S.O. server: Win64 5 | -- HeidiSQL Versione: 9.5.0.5196 6 | -- -------------------------------------------------------- 7 | 8 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 9 | /*!40101 SET NAMES utf8mb4 */; 10 | /*!50503 SET NAMES utf8mb4 */; 11 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 12 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 13 | 14 | 15 | -- Dump della struttura del database retrospy 16 | CREATE DATABASE IF NOT EXISTS `retrospy` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; 17 | USE `retrospy`; 18 | 19 | -- Dump della struttura di tabella retrospy.addrequests 20 | CREATE TABLE IF NOT EXISTS `addrequests` ( 21 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 22 | `profileid` int(10) unsigned NOT NULL DEFAULT 0, 23 | `targetid` int(11) unsigned NOT NULL DEFAULT 0, 24 | `syncrequested` varchar(255) NOT NULL DEFAULT '', 25 | `reason` varchar(255) NOT NULL DEFAULT '', 26 | PRIMARY KEY (`id`), 27 | UNIQUE KEY `id` (`id`), 28 | KEY `FK_addrequests_profiles` (`profileid`), 29 | KEY `FK_addrequests_profiles_2` (`targetid`), 30 | CONSTRAINT `FK_addrequests_profiles` FOREIGN KEY (`profileid`) REFERENCES `profiles` (`profileid`), 31 | CONSTRAINT `FK_addrequests_profiles_2` FOREIGN KEY (`targetid`) REFERENCES `profiles` (`profileid`) 32 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 33 | 34 | -- Dump dei dati della tabella retrospy.addrequests: ~0 rows (circa) 35 | /*!40000 ALTER TABLE `addrequests` DISABLE KEYS */; 36 | /*!40000 ALTER TABLE `addrequests` ENABLE KEYS */; 37 | 38 | -- Dump della struttura di tabella retrospy.blocked 39 | CREATE TABLE IF NOT EXISTS `blocked` ( 40 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 41 | `targetid` int(10) unsigned NOT NULL, 42 | `profileid` int(10) unsigned NOT NULL, 43 | PRIMARY KEY (`id`), 44 | UNIQUE KEY `id` (`id`), 45 | KEY `FK_blocked_profiles` (`profileid`), 46 | KEY `FK_blocked_profiles_2` (`targetid`), 47 | CONSTRAINT `FK_blocked_profiles` FOREIGN KEY (`profileid`) REFERENCES `profiles` (`profileid`), 48 | CONSTRAINT `FK_blocked_profiles_2` FOREIGN KEY (`targetid`) REFERENCES `profiles` (`profileid`) 49 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 50 | 51 | -- Dump dei dati della tabella retrospy.blocked: ~0 rows (circa) 52 | /*!40000 ALTER TABLE `blocked` DISABLE KEYS */; 53 | /*!40000 ALTER TABLE `blocked` ENABLE KEYS */; 54 | 55 | -- Dump della struttura di tabella retrospy.friends 56 | CREATE TABLE IF NOT EXISTS `friends` ( 57 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 58 | `profileid` int(10) unsigned NOT NULL DEFAULT 0, 59 | `targetid` int(10) unsigned NOT NULL DEFAULT 0, 60 | PRIMARY KEY (`id`), 61 | UNIQUE KEY `id` (`id`), 62 | KEY `FK_friends_profiles` (`profileid`), 63 | KEY `FK_friends_profiles_2` (`targetid`), 64 | CONSTRAINT `FK_friends_profiles` FOREIGN KEY (`profileid`) REFERENCES `profiles` (`profileid`), 65 | CONSTRAINT `FK_friends_profiles_2` FOREIGN KEY (`targetid`) REFERENCES `profiles` (`profileid`) 66 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 67 | 68 | -- Dump dei dati della tabella retrospy.friends: ~0 rows (circa) 69 | /*!40000 ALTER TABLE `friends` DISABLE KEYS */; 70 | /*!40000 ALTER TABLE `friends` ENABLE KEYS */; 71 | 72 | -- Dump della struttura di tabella retrospy.messages 73 | CREATE TABLE IF NOT EXISTS `messages` ( 74 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 75 | `from` int(10) unsigned NOT NULL, 76 | `to` int(10) unsigned NOT NULL, 77 | `date` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 78 | `message` varchar(200) NOT NULL, 79 | PRIMARY KEY (`id`), 80 | UNIQUE KEY `id` (`id`), 81 | KEY `FK_messages_profiles` (`from`), 82 | KEY `FK_messages_profiles_2` (`to`), 83 | CONSTRAINT `FK_messages_profiles` FOREIGN KEY (`from`) REFERENCES `profiles` (`profileid`), 84 | CONSTRAINT `FK_messages_profiles_2` FOREIGN KEY (`to`) REFERENCES `profiles` (`profileid`) 85 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 86 | 87 | -- Dump dei dati della tabella retrospy.messages: ~0 rows (circa) 88 | /*!40000 ALTER TABLE `messages` DISABLE KEYS */; 89 | /*!40000 ALTER TABLE `messages` ENABLE KEYS */; 90 | 91 | -- Dump della struttura di tabella retrospy.profiles 92 | CREATE TABLE IF NOT EXISTS `profiles` ( 93 | `profileid` int(11) unsigned NOT NULL AUTO_INCREMENT, 94 | `userid` int(11) unsigned NOT NULL DEFAULT 0, 95 | `sesskey` int(11) DEFAULT NULL, 96 | `uniquenick` varchar(20) NOT NULL DEFAULT '''''', 97 | `nick` varchar(30) NOT NULL DEFAULT '''''', 98 | `firstname` varchar(30) NOT NULL DEFAULT '''''', 99 | `lastname` varchar(30) NOT NULL DEFAULT '''''', 100 | `publicmask` int(11) NOT NULL DEFAULT 0, 101 | `deleted` tinyint(1) NOT NULL DEFAULT 0, 102 | `latitude` float NOT NULL DEFAULT 0, 103 | `longitude` float NOT NULL DEFAULT 0, 104 | `aim` varchar(50) DEFAULT '0', 105 | `picture` int(11) DEFAULT 0, 106 | `occupationid` int(11) DEFAULT 0, 107 | `incomeid` int(11) DEFAULT 0, 108 | `industryid` int(11) DEFAULT 0, 109 | `marriedid` int(11) DEFAULT 0, 110 | `childcount` int(11) DEFAULT 0, 111 | `interests1` int(11) DEFAULT 0, 112 | `ownership1` int(11) DEFAULT 0, 113 | `connectiontype` int(11) DEFAULT 0, 114 | `sex` enum('MALE','FEMALE','PAT') DEFAULT 'PAT', 115 | `zipcode` varchar(10) DEFAULT '00000', 116 | `countrycode` varchar(2) DEFAULT '0', 117 | `homepage` varchar(75) DEFAULT '0', 118 | `birthday` int(11) DEFAULT 0, 119 | `birthmonth` int(11) DEFAULT 0, 120 | `birthyear` int(11) DEFAULT 0, 121 | `location` varchar(127) DEFAULT '0', 122 | `icq` int(11) DEFAULT 0, 123 | PRIMARY KEY (`profileid`), 124 | UNIQUE KEY `profileid` (`profileid`), 125 | UNIQUE KEY `uniquenick` (`uniquenick`), 126 | UNIQUE KEY `sesskey` (`sesskey`), 127 | KEY `FK_profiles_users` (`userid`), 128 | CONSTRAINT `FK_profiles_users` FOREIGN KEY (`userid`) REFERENCES `users` (`userid`) 129 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4; 130 | 131 | -- Dump dei dati della tabella retrospy.profiles: ~2 rows (circa) 132 | /*!40000 ALTER TABLE `profiles` DISABLE KEYS */; 133 | INSERT INTO `profiles` (`profileid`, `userid`, `sesskey`, `uniquenick`, `nick`, `firstname`, `lastname`, `publicmask`, `deleted`, `latitude`, `longitude`, `aim`, `picture`, `occupationid`, `incomeid`, `industryid`, `marriedid`, `childcount`, `interests1`, `ownership1`, `connectiontype`, `sex`, `zipcode`, `countrycode`, `homepage`, `birthday`, `birthmonth`, `birthyear`, `location`, `icq`) VALUES 134 | (2, 1, NULL, 'SpyGuy', 'SpyGuy', 'Spy', 'Guy', 0, 0, 40.7142, -74.0064, 'spyguy@aim.com', 0, 0, 0, 0, 0, 0, 0, 0, 3, 'MALE', '10001', 'US', 'https://www.gamespy.com/', 20, 3, 1980, 'New York', 0), 135 | (3, 1, NULL, 'SpyGuy2', 'SpyGuy2', 'Spy', 'Guy', 0, 0, 40.7142, -74.0064, 'spyguy@aim.com', 0, 0, 0, 0, 0, 0, 0, 0, 3, 'MALE', '10001', 'US', 'https://www.gamespy.com/', 20, 3, 1980, 'New York', 0); 136 | /*!40000 ALTER TABLE `profiles` ENABLE KEYS */; 137 | 138 | -- Dump della struttura di tabella retrospy.users 139 | CREATE TABLE IF NOT EXISTS `users` ( 140 | `userid` int(11) unsigned NOT NULL AUTO_INCREMENT, 141 | `email` varchar(50) NOT NULL, 142 | `password` varchar(32) NOT NULL, 143 | `deleted` tinyint(1) NOT NULL DEFAULT 0, 144 | `emailverified` tinyint(1) NOT NULL DEFAULT 0, 145 | PRIMARY KEY (`userid`), 146 | UNIQUE KEY `userid` (`userid`) 147 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; 148 | 149 | -- Dump dei dati della tabella retrospy.users: ~0 rows (circa) 150 | /*!40000 ALTER TABLE `users` DISABLE KEYS */; 151 | INSERT INTO `users` (`userid`, `email`, `password`, `deleted`, `emailverified`) VALUES 152 | (1, 'spyguy@gamespy.com', '0000', 0, 1); 153 | /*!40000 ALTER TABLE `users` ENABLE KEYS */; 154 | 155 | /*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; 156 | /*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; 157 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 158 | -------------------------------------------------------------------------------- /RetroSpy.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameProgressive/RetroSpyServerCXX/f9936f676a31a486cf2c78187c9e6bccb584f7f7/RetroSpy.db -------------------------------------------------------------------------------- /common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | ${CMAKE_CURRENT_LIST_DIR}/chc_endian.cpp 3 | ${CMAKE_CURRENT_LIST_DIR}/chc_endian.h 4 | ${CMAKE_CURRENT_LIST_DIR}/Helper.cpp 5 | ${CMAKE_CURRENT_LIST_DIR}/Helper.h 6 | ${CMAKE_CURRENT_LIST_DIR}/Helper_Base64.cpp 7 | ${CMAKE_CURRENT_LIST_DIR}/Helper_Query.cpp 8 | ${CMAKE_CURRENT_LIST_DIR}/Helper_Random.cpp 9 | ${CMAKE_CURRENT_LIST_DIR}/md5.c 10 | ${CMAKE_CURRENT_LIST_DIR}/md5.h 11 | ${CMAKE_CURRENT_LIST_DIR}/TemplateStringServer.cpp 12 | ${CMAKE_CURRENT_LIST_DIR}/TemplateStringServer.h 13 | ) 14 | 15 | add_library(RetroSpyCommon STATIC ${SOURCES}) 16 | target_link_libraries(RetroSpyCommon MDK) 17 | 18 | -------------------------------------------------------------------------------- /common/Defines.h: -------------------------------------------------------------------------------- 1 | #ifndef _RETROSPY_DEFINES_HEADER_ 2 | #define _RETROSPY_DEFINES_HEADER_ 3 | 4 | #include 5 | 6 | typedef enum _GPEnum 7 | { 8 | // Callbacks 9 | //////////// 10 | GP_ERROR = 0, 11 | GP_RECV_BUDDY_REQUEST, 12 | GP_RECV_BUDDY_STATUS, 13 | GP_RECV_BUDDY_MESSAGE, 14 | GP_RECV_BUDDY_UTM, 15 | GP_RECV_GAME_INVITE, 16 | GP_TRANSFER_CALLBACK, 17 | GP_RECV_BUDDY_AUTH, 18 | GP_RECV_BUDDY_REVOKE, 19 | 20 | // Global States. 21 | ///////////////// 22 | GP_INFO_CACHING = 0x0100, 23 | GP_SIMULATION, 24 | GP_INFO_CACHING_BUDDY_AND_BLOCK_ONLY, 25 | 26 | // Blocking 27 | /////////// 28 | GP_BLOCKING = 1, 29 | GP_NON_BLOCKING = 0, 30 | 31 | // Firewall 32 | /////////// 33 | GP_FIREWALL = 1, 34 | GP_NO_FIREWALL = 0, 35 | 36 | // Check Cache 37 | ////////////// 38 | GP_CHECK_CACHE = 1, 39 | GP_DONT_CHECK_CACHE = 0, 40 | 41 | // Is Valid Email. 42 | // PANTS|02.15.00 43 | ////////////////// 44 | GP_VALID = 1, 45 | GP_INVALID = 0, 46 | 47 | // Fatal Error. 48 | /////////////// 49 | GP_FATAL = 1, 50 | GP_NON_FATAL = 0, 51 | 52 | // Sex 53 | ////// 54 | GP_MALE = 0x0500, 55 | GP_FEMALE, 56 | GP_PAT, 57 | 58 | // Profile Search. 59 | ////////////////// 60 | GP_MORE = 0x0600, 61 | GP_DONE, 62 | 63 | // Set Info 64 | /////////// 65 | GP_NICK = 0x0700, 66 | GP_UNIQUENICK, 67 | GP_EMAIL, 68 | GP_PASSWORD, 69 | GP_FIRSTNAME, 70 | GP_LASTNAME, 71 | GP_ICQUIN, 72 | GP_HOMEPAGE, 73 | GP_ZIPCODE, 74 | GP_COUNTRYCODE, 75 | GP_BIRTHDAY, 76 | GP_SEX, 77 | GP_CPUBRANDID, 78 | GP_CPUSPEED, 79 | GP_MEMORY, 80 | GP_VIDEOCARD1STRING, 81 | GP_VIDEOCARD1RAM, 82 | GP_VIDEOCARD2STRING, 83 | GP_VIDEOCARD2RAM, 84 | GP_CONNECTIONID, 85 | GP_CONNECTIONSPEED, 86 | GP_HASNETWORK, 87 | GP_OSSTRING, 88 | GP_AIMNAME, // PANTS|03.20.01 89 | GP_PIC, 90 | GP_OCCUPATIONID, 91 | GP_INDUSTRYID, 92 | GP_INCOMEID, 93 | GP_MARRIEDID, 94 | GP_CHILDCOUNT, 95 | GP_INTERESTS1, 96 | 97 | // New Profile. 98 | /////////////// 99 | GP_REPLACE = 1, 100 | GP_DONT_REPLACE = 0, 101 | 102 | // Is Connected. 103 | //////////////// 104 | GP_CONNECTED = 1, 105 | GP_NOT_CONNECTED = 0, 106 | 107 | // Public mask. 108 | /////////////// 109 | GP_MASK_NONE = 0x00000000, 110 | GP_MASK_HOMEPAGE = 0x00000001, 111 | GP_MASK_ZIPCODE = 0x00000002, 112 | GP_MASK_COUNTRYCODE = 0x00000004, 113 | GP_MASK_BIRTHDAY = 0x00000008, 114 | GP_MASK_SEX = 0x00000010, 115 | GP_MASK_EMAIL = 0x00000020, 116 | GP_MASK_ALL = 0xFFFFFFFF, 117 | 118 | // Status 119 | ///////// 120 | GP_OFFLINE = 0, 121 | GP_ONLINE = 1, 122 | GP_PLAYING = 2, 123 | GP_STAGING = 3, 124 | GP_CHATTING = 4, 125 | GP_AWAY = 5, 126 | 127 | // Session flags 128 | ///////////////// 129 | GP_SESS_IS_CLOSED = 0x00000001, 130 | GP_SESS_IS_OPEN = 0x00000002, 131 | GP_SESS_HAS_PASSWORD = 0x00000004, 132 | GP_SESS_IS_BEHIND_NAT = 0x00000008, 133 | GP_SESS_IS_RANKED = 0x000000010, 134 | 135 | 136 | // CPU Brand ID 137 | /////////////// 138 | GP_INTEL = 1, 139 | GP_AMD, 140 | GP_CYRIX, 141 | GP_MOTOROLA, 142 | GP_ALPHA, 143 | 144 | // Connection ID. 145 | ///////////////// 146 | GP_MODEM = 1, 147 | GP_ISDN, 148 | GP_CABLEMODEM, 149 | GP_DSL, 150 | GP_SATELLITE, 151 | GP_ETHERNET, 152 | GP_WIRELESS, 153 | 154 | // Transfer callback type. 155 | // *** the transfer is ended when these types are received 156 | ////////////////////////// 157 | GP_TRANSFER_SEND_REQUEST = 0x800, // arg->num == numFiles 158 | GP_TRANSFER_ACCEPTED, 159 | GP_TRANSFER_REJECTED, // *** 160 | GP_TRANSFER_NOT_ACCEPTING, // *** 161 | GP_TRANSFER_NO_CONNECTION, // *** 162 | GP_TRANSFER_DONE, // *** 163 | GP_TRANSFER_CANCELLED, // *** 164 | GP_TRANSFER_LOST_CONNECTION, // *** 165 | GP_TRANSFER_ERROR, // *** 166 | GP_TRANSFER_THROTTLE, // arg->num == Bps 167 | GP_FILE_BEGIN, 168 | GP_FILE_PROGRESS, // arg->num == numBytes 169 | GP_FILE_END, 170 | GP_FILE_DIRECTORY, 171 | GP_FILE_SKIP, 172 | GP_FILE_FAILED, // arg->num == error 173 | 174 | // GP_FILE_FAILED error 175 | /////////////////////// 176 | GP_FILE_READ_ERROR = 0x900, 177 | GP_FILE_WRITE_ERROR, 178 | GP_FILE_DATA_ERROR, 179 | 180 | // Transfer Side. 181 | ///////////////// 182 | GP_TRANSFER_SENDER = 0xA00, 183 | GP_TRANSFER_RECEIVER, 184 | 185 | // UTM send options. 186 | //////////////////// 187 | GP_DONT_ROUTE = 0xB00, // only send direct 188 | 189 | // Quiet mode flags. 190 | //////////////////// 191 | GP_SILENCE_NONE = 0x00000000, 192 | GP_SILENCE_MESSAGES = 0x00000001, 193 | GP_SILENCE_UTMS = 0x00000002, 194 | GP_SILENCE_LIST = 0x00000004, // includes requests, auths, and revokes 195 | GP_SILENCE_ALL = 0xFFFFFFFF, 196 | 197 | // Flags for checking if newer version of status info is supported 198 | GP_NEW_STATUS_INFO_SUPPORTED = 0xC00, 199 | GP_NEW_STATUS_INFO_NOT_SUPPORTED = 0xC01, 200 | 201 | // Error codes that can occur while creating a new user. 202 | GP_NEWUSER = 512, // 0x200, There was an error creating a new user. 203 | GP_NEWUSER_BAD_NICK = 513, // 0x201, A profile with that nick already exists. 204 | GP_NEWUSER_BAD_PASSWORD = 514, // 0x202, The password does not match the email address. 205 | GP_NEWUSER_UNIQUENICK_INVALID = 515, // 0x203, The uniquenick is invalid. 206 | GP_NEWUSER_UNIQUENICK_INUSE = 516, // 0x204, The uniquenick is already in use. 207 | 208 | // Error codes that can occur while checking whether a user exists. 209 | GP_CHECK = 3584, // 0xE00, There was an error checking the user account. 210 | GP_CHECK_BAD_EMAIL = 3585, // 0xE01, No account exists with the provided e-mail address. 211 | GP_CHECK_BAD_NICK = 3586, // 0xE02, No such profile exists for the provided e-mail address. 212 | GP_CHECK_BAD_PASSWORD = 3587, // 0xE03, The password is incorrect. 213 | 214 | } GPEnum; 215 | 216 | #define GS_REQUEST_LEN 20 217 | #define GS_GAMENAME_LEN 64 218 | #define GP_EMAIL_LEN 51 219 | #define GP_PASSWORD_LEN 31 220 | #define GP_PASSWORDENC_LEN ((((GP_PASSWORD_LEN+2)*4)/3)+1) 221 | #define GP_PARTNERID_LEN sizeof(int) 222 | #define GP_NAMESPACEID_LEN sizeof(int) 223 | #define GP_NICK_LEN 31 224 | #define GP_UNIQUENICK_LEN 21 225 | #define GP_XOR_SEED 0x79707367 // "gspy" 226 | #define GP_STATUS_STRING_LEN 256 227 | #define GP_FIRSTNAME_LEN 31 228 | #define GP_LASTNAME_LEN 31 229 | #define GP_HOMEPAGE_LEN 76 230 | #define GP_ZIPCODE_LEN 11 231 | #define GP_COUNTRYCODE_LEN 3 232 | #define GP_AIMNAME_LEN 51 233 | #define GP_LOGIN_TICKET_LEN 25 234 | #define GP_LOCATION_STRING_LEN 256 235 | #define GS_PARTNER_ID 0 236 | #define GP_SERVERCHALL_LEN 11 237 | #define GP_AUTHTOKEN_LEN 256 238 | #define GP_PARTNERCHALLENGE_LEN 256 239 | #define GP_CLIENTCHALL_LEN 64 240 | #define GP_PLACE_LEN 128 241 | 242 | #define MD5_BUFFER_LEN 33 243 | 244 | typedef struct 245 | { 246 | char nick[GP_NICK_LEN]; 247 | char uniquenick[GP_UNIQUENICK_LEN]; 248 | char email[GP_EMAIL_LEN]; 249 | char firstname[GP_FIRSTNAME_LEN]; 250 | char lastname[GP_LASTNAME_LEN]; 251 | char homepage[GP_HOMEPAGE_LEN]; 252 | int icquin; 253 | char zipcode[GP_ZIPCODE_LEN]; 254 | char countrycode[GP_COUNTRYCODE_LEN]; 255 | float longitude; // negative is west, positive is east. (0, 0) means unknown. 256 | float latitude; // negative is south, positive is north. (0, 0) means unknown. 257 | char place[GP_PLACE_LEN]; // e.g., "USA|California|Irvine", "South Korea|Seoul", "Turkey" 258 | int birthday; 259 | int birthmonth; 260 | int birthyear; 261 | GPEnum sex; 262 | int publicmask; 263 | char aimname[GP_AIMNAME_LEN]; 264 | int pic; 265 | int occupationid; 266 | int industryid; 267 | int incomeid; 268 | int marriedid; 269 | int childcount; 270 | int interests1; 271 | int ownership1; 272 | int conntypeid; 273 | } GPIInfoCache; 274 | 275 | #if _WIN32 && _MSC_VER 276 | #include 277 | #ifdef __cplusplus 278 | #define RetroSpyModuleStart extern "C" { __declspec(dllexport) int MDKModule(void* data) { 279 | #else 280 | #define RetroSpyModuleStart __declspec(dllexport) int MDKModule(void* data) { 281 | #endif 282 | #else 283 | #ifdef __cplusplus 284 | #define RetroSpyModuleStart extern "C" { int MDKModule(void* data) { 285 | #else 286 | #define RetroSpyModuleStart int MDKModule(void* data) { 287 | #endif 288 | #endif 289 | #ifdef __cplusplus 290 | #define RetroSpyModuleEnd Server->Run(); return ERROR_NONE; }} 291 | #else 292 | #define RetroSpyModuleEnd return ERROR_NONE; } 293 | #endif 294 | #endif 295 | -------------------------------------------------------------------------------- /common/Helper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Foobar is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with Foobar. If not, see . 16 | */ 17 | #include "Helper.h" 18 | 19 | #include "md5.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | const char cvdallowed[] = "1234567890#" 27 | "_-`()$-=;/[]" 28 | "@+&%" 29 | "abcdefghijklmnopqrstuvwxyz" 30 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 31 | 32 | 33 | void gs_pass_decode(const char *in, char *out) 34 | { 35 | size_t pass_len = strlen(in), out_len = B64DecodeLen(in, 1), i = 0; 36 | 37 | RandSeed(GP_XOR_SEED); 38 | B64Decode(in, out, pass_len, &out_len, 1); 39 | 40 | for (; i < out_len; i++) 41 | out[i] ^= (char)(RandInt(0, 0xFF)); 42 | 43 | out[out_len] = '\0'; 44 | } 45 | 46 | void gs_pass_decode(std::string& str) 47 | { 48 | size_t pass_len = str.length(), out_len = B64DecodeLen(str.c_str(), 1), i = 0; 49 | char* out = (char*)malloc(out_len + 1); 50 | 51 | RandSeed(GP_XOR_SEED); 52 | B64Decode(str.c_str(), out, pass_len, &out_len, 1); 53 | 54 | for (; i < out_len; i++) 55 | out[i] ^= (char)(RandInt(0, 0xFF)); 56 | 57 | out[out_len] = '\0'; 58 | 59 | str = out; 60 | } 61 | 62 | bool charValid(char ch) 63 | { 64 | int i = 0; 65 | for (; i < sizeof(cvdallowed); i++) 66 | { 67 | if (cvdallowed[i] == ch) 68 | return true; 69 | } 70 | 71 | return false; 72 | } 73 | 74 | void gs_make_valid(char *name) 75 | { 76 | size_t i = 0; 77 | for (; i < strlen(name); i++) 78 | { 79 | if (!charValid(name[i])) 80 | name[i] = '_'; 81 | } 82 | } 83 | 84 | void hash_md5(const char *what, size_t len, char *out) 85 | { 86 | unsigned char md5h[16]; 87 | static const char hex[] = "0123456789abcdef"; 88 | md5_context md5t; 89 | size_t i = 0; 90 | 91 | md5_starts(&md5t); 92 | md5_update(&md5t, (unsigned char *)what, (int)len); 93 | md5_finish(&md5t, md5h); 94 | 95 | for (i = 0; i < 16; i++) { 96 | *out++ = hex[md5h[i] >> 4]; 97 | *out++ = hex[md5h[i] & 15]; 98 | } 99 | *out = 0; 100 | } 101 | 102 | void gs_do_proof(char *out, const char *password, const char *token, const char *serverch, const char *clientch) 103 | { 104 | char passmd5[MD5_BUFFER_LEN], buffer[512]; 105 | passmd5[0] = buffer[0] = 0; 106 | 107 | /* Hash the decrypted password */ 108 | hash_md5(password, strlen(password), passmd5); 109 | 110 | /* Generate the buffer */ 111 | snprintf(buffer, sizeof(buffer), "%s%s%s%s%s%s", 112 | passmd5, 113 | " ", 114 | token, 115 | serverch, 116 | clientch, 117 | passmd5); 118 | 119 | /* Hash the buffer */ 120 | hash_md5(buffer, strlen(buffer), out); 121 | } 122 | 123 | bool user_to_emailnick(const char *buffer, char *lpEmail, size_t email_size, char *lpNick, size_t nick_size) 124 | { 125 | char *pch = NULL; 126 | size_t buffersize = 0, pos = 0; 127 | 128 | /* Check if the parametras are NULL */ 129 | if (buffer == NULL) 130 | return false; 131 | if (lpEmail == NULL) 132 | return false; 133 | if (lpNick == NULL) 134 | return false; 135 | 136 | buffersize = strlen(buffer); 137 | 138 | /* Get @ position*/ 139 | pch = (char*)strchr(buffer, '@'); 140 | 141 | if (pch == NULL) 142 | return false; /* Dosen't exists */ 143 | 144 | pos = pch - buffer; 145 | 146 | if (pos > nick_size) 147 | return false; /* Email readed too big to store into the buffer */ 148 | 149 | if ((buffersize - pos) > email_size) 150 | return false; /* Nick readed too big to store into the buffer */ 151 | 152 | strncpy(lpNick, buffer, pos); 153 | lpNick[pos] = '\0'; 154 | strncpy(lpEmail, &buffer[pos + 1], buffersize-pos-1); 155 | lpEmail[buffersize - pos-1] = '\0'; 156 | 157 | return true; 158 | } 159 | 160 | bool is_gs_valid(const char *base) 161 | { 162 | int len = strlen(base); 163 | 164 | if (base[0] != '\\') 165 | return false; 166 | 167 | if (strcmp(&base[len - 7], "\\final\\") != 0) 168 | return false; 169 | 170 | return true; 171 | } 172 | 173 | size_t get_gs_req(const char *base, char *out, size_t max_size) 174 | { 175 | char *pch = NULL; 176 | const char *in = &base[1]; 177 | size_t pos = 0; 178 | 179 | pch = (char*)strstr(in, "\\"); 180 | 181 | if (pch == NULL) 182 | return -1; 183 | 184 | pos = pch-in; 185 | 186 | if (max_size < pos) 187 | return -1; 188 | 189 | strncpy(out, in, pos); 190 | out[pos] = '\0'; 191 | 192 | pos += 1; /* First \\ */ 193 | 194 | if (in[pos] == '\\') 195 | return pos + 2; /* Double slash handling */ 196 | 197 | return pos + 1; 198 | } 199 | 200 | bool get_gs_data(std::string input, std::string& out, const char* what) 201 | { 202 | char possible[1024]; 203 | if (!get_gs_data(input.c_str(), what, possible, 1024)) 204 | return false; 205 | 206 | out = possible; 207 | return true; 208 | } 209 | 210 | char* get_gs_data(const char *base, const char *what, char *out, size_t max_size) 211 | { 212 | char *pch = NULL, *bx = NULL; 213 | size_t i2 = 0, i = 0; 214 | bool bfound = false, bRun = true; 215 | 216 | out[0] = '\0'; 217 | 218 | while (bRun) 219 | { 220 | char *tmp = NULL; 221 | bx = (char *)&base[i2]; 222 | 223 | pch = strchr(bx, '\\'); 224 | 225 | if (pch == NULL) 226 | break; 227 | 228 | i = pch - bx; 229 | 230 | tmp = (char*)malloc(i + 1); 231 | 232 | strncpy(tmp, bx, i); 233 | tmp[i] = '\0'; 234 | 235 | if (bfound) 236 | { 237 | if (i < max_size) 238 | { 239 | strncpy(out, tmp, i); 240 | out[i] = '\0'; 241 | 242 | free(tmp); 243 | } 244 | 245 | bRun = false; 246 | } 247 | else 248 | { 249 | if (strcmp(tmp, what) == 0) 250 | bfound = true; 251 | } 252 | 253 | if (bRun) 254 | { 255 | free(tmp); 256 | i2 += i + 1; 257 | } 258 | } 259 | 260 | return out; 261 | } 262 | 263 | bool match_mask_with_name2(const char *mask, const char *name) 264 | { 265 | const unsigned char *m = (unsigned char *)mask; 266 | const unsigned char *n = (unsigned char *)name; 267 | const unsigned char *ma = NULL; 268 | const unsigned char *na = (unsigned char *)name; 269 | 270 | while(true) 271 | { 272 | if (*m == '*') 273 | { 274 | while (*m == '*') /* collapse.. */ 275 | m++; 276 | ma = m; 277 | na = n; 278 | } 279 | 280 | if (!*m) 281 | { 282 | if (!*n) 283 | return false; 284 | if (!ma) 285 | return true; 286 | for (m--; (m > (const unsigned char *)mask) && (*m == '?'); m--); 287 | if (*m == '*') 288 | return false; 289 | m = ma; 290 | n = ++na; 291 | } else 292 | if (!*n) 293 | { 294 | while (*m == '*') /* collapse.. */ 295 | m++; 296 | return (*m != 0); 297 | } 298 | 299 | if ((tolower(*m) != tolower(*n)) && !((*m == '_') && (*n == ' ')) && (*m != '?')) 300 | { 301 | if (!ma) 302 | return true; 303 | m = ma; 304 | n = ++na; 305 | } else 306 | { 307 | m++; 308 | n++; 309 | } 310 | } 311 | 312 | return true; 313 | } 314 | 315 | bool match_mask_with_name(const char *mask, const char *name) 316 | { 317 | if (mask[0] == '*' && mask[1] == '!') { 318 | mask += 2; 319 | while (*name != '!' && *name) 320 | name++; 321 | if (!*name) 322 | return true; 323 | name++; 324 | } 325 | 326 | if (mask[0] == '*' && mask[1] == '@') { 327 | mask += 2; 328 | while (*name != '@' && *name) 329 | name++; 330 | if (!*name) 331 | return true; 332 | name++; 333 | } 334 | 335 | return match_mask_with_name2(mask,name); 336 | } 337 | -------------------------------------------------------------------------------- /common/Helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef RETROSPYCOMMON_HELPER_H 18 | #define RETROSPYCOMMON_HELPER_H 19 | 20 | #include "Defines.h" 21 | #include 22 | 23 | #include 24 | 25 | // Base64 26 | void B64Decode(const char *input, char *output, size_t inlen, size_t * outlen, int encodingType); 27 | void B64Encode(const char *input, char *output, size_t inlen, int encodingType); 28 | size_t B64DecodeLen(const char *input, int encodingType); 29 | 30 | // Random 31 | void RandSeed(unsigned long seed); 32 | int RandInt(int low, int high); 33 | 34 | // Helper 35 | void gs_pass_decode(const char *buf, char *out); 36 | void gs_pass_decode(std::string& string); 37 | void gs_make_valid(char *name); 38 | void gs_do_proof(char *out, const char *password, const char *token, const char *serverch, const char *clientch); 39 | void hash_md5(const char *what, size_t len, char *out); 40 | 41 | // Database 42 | bool GetProfileIDFromNickEmailAndPass(CDatabase* c, const char *nick, const char *email, const char* pass, unsigned int* id); 43 | bool GetProfileIDFromNickEmail(CDatabase* c, const char *nick, const char *email, unsigned int* pid); 44 | void GetUniqueNickFromProfileID(CDatabase* c, unsigned int pid, char *unick, int size); 45 | bool GetProfileIDFromUniqueNick(CDatabase* db, const char *unick, unsigned int* out); 46 | void GetPasswordFromUserID(CDatabase* c, char *out, int out_len, unsigned int id); 47 | unsigned int GetUserIDFromProfileID(CDatabase* db, unsigned int id, unsigned int* out); 48 | int AssignSessionKeyFromProfileID(CDatabase* c, unsigned int id); 49 | void FreeSessionKey(CDatabase* c, unsigned int profileid); 50 | bool GetProfileInfo(CDatabase* c, unsigned int pid, GPIInfoCache *out, unsigned int *id_out); 51 | bool GetProfileIDFromSessKey(CDatabase* db, unsigned int seeskey, unsigned int* out); 52 | bool GetProfileIDFromAuthToken(CDatabase* db, const char* authtoken, unsigned int *out); 53 | bool GetUserIDFromEmail(CDatabase* db, const char* email, unsigned int* id); 54 | int RegisterUser(CDatabase* db, const char* email, const char* nick, const char* pass, unsigned int* userid); 55 | 56 | //String 57 | bool user_to_emailnick(const char *buffer, char *lpEmail, size_t email_size, char *lpNick, size_t nick_size); 58 | bool is_gs_valid(const char *base); 59 | size_t get_gs_req(const char *base, char *out, size_t max_size); 60 | char* get_gs_data(const char *base, const char *what, char *out, size_t max_size); 61 | bool get_gs_data(std::string base, std::string& out, const char* what); 62 | 63 | // Mask 64 | bool match_mask_with_name(const char *mask, const char *name); 65 | bool match_mask_with_name2(const char *mask, const char *name); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /common/Helper_Base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "Helper.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | static void QuartToTrip(char *quart, char *trip, size_t inlen) 26 | { 27 | if (inlen >= 2) 28 | trip[0] = (char)(quart[0] << 2 | quart[1] >> 4); 29 | if (inlen >= 3) 30 | trip[1] = (char)((quart[1] & 0x0F) << 4 | quart[2] >> 2); 31 | if (inlen >= 4) 32 | trip[2] = (char)((quart[2] & 0x3) << 6 | quart[3]); 33 | } 34 | 35 | static void TripToQuart(const char *trip, char *quart, size_t inlen) 36 | { 37 | unsigned char triptemp[3]; 38 | size_t i; 39 | for (i = 0; i < inlen; i++) 40 | { 41 | triptemp[i] = (unsigned char)trip[i]; 42 | } 43 | while (i < 3) //fill the rest with 0 44 | { 45 | triptemp[i] = 0; 46 | i++; 47 | } 48 | quart[0] = (char)(triptemp[0] >> 2); 49 | quart[1] = (char)(((triptemp[0] & 3) << 4) | (triptemp[1] >> 4)); 50 | quart[2] = (char)((triptemp[1] & 0x0F) << 2 | (triptemp[2] >> 6)); 51 | quart[3] = (char)(triptemp[2] & 0x3F); 52 | 53 | } 54 | 55 | const char defaultEncoding[] = { '+','/','=' }; 56 | const char alternateEncoding[] = { '[',']','_' }; 57 | const char urlSafeEncodeing[] = { '-','_','=' }; 58 | 59 | void B64Decode(const char *input, char *output, size_t inlen, size_t * outlen, int encodingType) 60 | { 61 | const char *encoding = 0; 62 | size_t readpos = 0; 63 | int writepos = 0; 64 | char block[4]; 65 | 66 | //int outlen = -1; 67 | //int inlen = (int)strlen(input); 68 | 69 | // 10-31-2004 : Added by Saad Nader 70 | // now supports URL safe encoding 71 | //////////////////////////////////////////////// 72 | switch (encodingType) 73 | { 74 | case 1: 75 | encoding = alternateEncoding; 76 | break; 77 | case 2: 78 | encoding = urlSafeEncodeing; 79 | break; 80 | default: encoding = defaultEncoding; 81 | } 82 | 83 | assert(inlen >= 0); 84 | if (inlen <= 0) 85 | { 86 | if (outlen) 87 | *outlen = 0; 88 | output[0] = '\0'; 89 | return; 90 | } 91 | 92 | // Break at end of string or padding character 93 | while (readpos < inlen && input[readpos] != encoding[2]) 94 | { 95 | // 'A'-'Z' maps to 0-25 96 | // 'a'-'z' maps to 26-51 97 | // '0'-'9' maps to 52-61 98 | // 62 maps to encoding[0] 99 | // 63 maps to encoding[1] 100 | if (input[readpos] >= '0' && input[readpos] <= '9') 101 | block[readpos % 4] = (char)(input[readpos] - 48 + 52); 102 | else if (input[readpos] >= 'a' && input[readpos] <= 'z') 103 | block[readpos % 4] = (char)(input[readpos] - 71); 104 | else if (input[readpos] >= 'A' && input[readpos] <= 'Z') 105 | block[readpos % 4] = (char)(input[readpos] - 65); 106 | else if (input[readpos] == encoding[0]) 107 | block[readpos % 4] = 62; 108 | else if (input[readpos] == encoding[1]) 109 | block[readpos % 4] = 63; 110 | 111 | // padding or '\0' characters also mark end of input 112 | else if (input[readpos] == encoding[2]) 113 | break; 114 | else if (input[readpos] == '\0') 115 | break; 116 | else 117 | { 118 | // (assert(0)); //bad input data 119 | if (outlen) 120 | *outlen = 0; 121 | output[0] = '\0'; 122 | return; //invaid data 123 | } 124 | 125 | // every 4 bytes, convert QuartToTrip into destination 126 | if (readpos % 4 == 3) // zero based, so (3%4) means four bytes, 0-1-2-3 127 | { 128 | QuartToTrip(block, &output[writepos], 4); 129 | writepos += 3; 130 | } 131 | readpos++; 132 | } 133 | 134 | // Convert any leftover characters in block 135 | if ((readpos != 0) && (readpos % 4 != 0)) 136 | { 137 | // fill block with pad (required for QuartToTrip) 138 | memset(&block[readpos % 4], encoding[2], (unsigned int)4 - (readpos % 4)); 139 | QuartToTrip(block, &output[writepos], readpos % 4); 140 | 141 | // output bytes depend on the number of non-pad input bytes 142 | if (readpos % 4 == 3) 143 | writepos += 2; 144 | else 145 | writepos += 1; 146 | } 147 | 148 | if (outlen) 149 | *outlen = writepos; 150 | } 151 | 152 | void B64Encode(const char *input, char *output, size_t inlen, int encodingType) 153 | { 154 | const char *encoding; 155 | char *holdout = output; 156 | char *lastchar; 157 | size_t todo = inlen; 158 | 159 | // 10-31-2004 : Added by Saad Nader 160 | // now supports URL safe encoding 161 | //////////////////////////////////////////////// 162 | switch (encodingType) 163 | { 164 | case 1: 165 | encoding = alternateEncoding; 166 | break; 167 | case 2: 168 | encoding = urlSafeEncodeing; 169 | break; 170 | default: encoding = defaultEncoding; 171 | } 172 | 173 | //assume interval of 3 174 | while (todo > 0) 175 | { 176 | #ifdef _WIN32 177 | TripToQuart(input, output, min(todo, 3)); 178 | #else 179 | TripToQuart(input, output, std::min(todo, 3)); 180 | #endif 181 | output += 4; 182 | input += 3; 183 | todo -= 3; 184 | } 185 | lastchar = output; 186 | if (inlen % 3 == 1) 187 | lastchar -= 2; 188 | else if (inlen % 3 == 2) 189 | lastchar -= 1; 190 | *output = 0; //null terminate! 191 | while (output > holdout) 192 | { 193 | output--; 194 | if (output >= lastchar) //pad the end 195 | *output = encoding[2]; 196 | else if (*output <= 25) 197 | *output = (char)(*output + 65); 198 | else if (*output <= 51) 199 | *output = (char)(*output + 71); 200 | else if (*output <= 61) 201 | *output = (char)(*output + 48 - 52); 202 | else if (*output == 62) 203 | *output = encoding[0]; 204 | else if (*output == 63) 205 | *output = encoding[1]; 206 | } 207 | } 208 | 209 | size_t B64DecodeLen(const char *input, int encodingType) 210 | { 211 | const char *encoding; 212 | const char *holdin = input; 213 | 214 | switch (encodingType) 215 | { 216 | case 1: 217 | encoding = alternateEncoding; 218 | break; 219 | case 2: 220 | encoding = urlSafeEncodeing; 221 | break; 222 | default: encoding = defaultEncoding; 223 | } 224 | 225 | while (*input) 226 | { 227 | if (*input == encoding[2]) 228 | return (input - holdin) / 4 * 3 + (input - holdin - 1) % 4; 229 | input++; 230 | } 231 | 232 | return (input - holdin) / 4 * 3; 233 | } 234 | -------------------------------------------------------------------------------- /common/Helper_Query.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Foobar is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with Foobar. If not, see . 16 | */ 17 | #include "Helper.h" 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | bool ExecuteFirstQuery(CDatabase* db, CResultSet *res, std::string query) 26 | { 27 | if (!res->ExecuteQuery(db, query)) 28 | return false; 29 | 30 | if (!res->GotoFirstRow()) 31 | return false; 32 | 33 | return true; 34 | } 35 | 36 | bool GetProfileIDFromNickEmail(CDatabase* db, const char *nick, const char *email, unsigned int* pid) 37 | { 38 | std::string query = ""; 39 | std::string _email = email, _nick = nick; 40 | CResultSet *res = NULL; 41 | 42 | query = "SELECT profiles.profileid FROM profiles INNER JOIN" 43 | " users ON profiles.userid=users.userid WHERE" 44 | " users.email='"; 45 | if (!mdk_escape_query_string(db, _email)) 46 | return false; 47 | query += _email; 48 | query += "' AND profiles.nick='"; 49 | if (!mdk_escape_query_string(db, _nick)) 50 | return false; 51 | query += _nick; 52 | query += "'"; 53 | 54 | res = new CResultSet(); 55 | if (!ExecuteFirstQuery(db, res, query)) 56 | { 57 | delete res; 58 | return false; 59 | } 60 | 61 | *pid = res->GetUIntFromRow(0); 62 | 63 | delete res; 64 | return true; 65 | } 66 | 67 | bool GetProfileIDFromNickEmailAndPass(CDatabase* c, const char *nick, const char *email, const char* pass, unsigned int* id) 68 | { 69 | std::string query = ""; 70 | std::string _email = email, _nick = nick, _pass = pass; 71 | CResultSet* res = NULL; 72 | 73 | query = "SELECT profiles.profileid FROM profiles INNER JOIN" 74 | " users ON profiles.userid=users.userid WHERE" 75 | " users.email='"; 76 | 77 | if (!mdk_escape_query_string(c, _email)) 78 | return false; 79 | 80 | query += _email; 81 | query += "' AND profiles.nick='"; 82 | 83 | if (!mdk_escape_query_string(c, _nick)) 84 | return false; 85 | 86 | query += _nick; 87 | query += "' AND users.password='"; 88 | 89 | if (!mdk_escape_query_string(c, _pass)) 90 | return false; 91 | 92 | query += "'"; 93 | 94 | res = new CResultSet(); 95 | 96 | if (!ExecuteFirstQuery(c, res, query)) 97 | { 98 | delete res; 99 | return false; 100 | } 101 | 102 | *id = res->GetUIntFromRow(0); 103 | 104 | delete res; 105 | return true; 106 | } 107 | 108 | bool GetUserIDFromEmail(CDatabase* db, const char* email, unsigned int* id) 109 | { 110 | std::string _email = email, query = ""; 111 | CResultSet* res = NULL; 112 | 113 | if (!mdk_escape_query_string(db, _email)) 114 | return false; 115 | 116 | query = "SELECT userid FROM users WHERE email='"; 117 | query += _email; 118 | query += "'"; 119 | 120 | res = new CResultSet(); 121 | if (!ExecuteFirstQuery(db, res, query)) 122 | { 123 | delete res; 124 | return false; 125 | } 126 | 127 | *id = res->GetUIntFromRow(0); 128 | 129 | delete res; 130 | return true; 131 | } 132 | 133 | void GetUniqueNickFromProfileID(CDatabase* db, unsigned int pid, char *unick, int size) 134 | { 135 | std::string query = ""; 136 | CResultSet *res = new CResultSet(); 137 | 138 | query = "SELECT uniquenick FROM profiles WHERE profileid='"; 139 | query += std::to_string(pid); 140 | query += "'"; 141 | 142 | if (!ExecuteFirstQuery(db, res, query)) 143 | { 144 | delete res; 145 | return; 146 | } 147 | 148 | strncpy(unick, res->GetStringFromRow(0).c_str(), size); 149 | unick[size - 1] = '\0'; 150 | 151 | delete res; 152 | } 153 | 154 | bool GetProfileIDFromUniqueNick(CDatabase* db, const char *unick, unsigned int* out) 155 | { 156 | std::string query = "", _unick = unick; 157 | CResultSet *res = new CResultSet(); 158 | 159 | query = "SELECT profileid FROM profiles WHERE uniquenick='"; 160 | if (!mdk_escape_query_string(db, _unick)) 161 | { 162 | delete res; 163 | return false; 164 | } 165 | query += _unick; 166 | query += "'"; 167 | 168 | if (!ExecuteFirstQuery(db, res, query)) 169 | { 170 | delete res; 171 | return false; 172 | } 173 | 174 | *out = res->GetUIntFromRow(0); 175 | 176 | delete res; 177 | return true; 178 | } 179 | 180 | void GetPasswordFromUserID(CDatabase* db, char *out, int out_len, unsigned int id) 181 | { 182 | CResultSet *res = new CResultSet(); 183 | char query[61]; 184 | query[0] = 0; 185 | 186 | snprintf(query, sizeof(query), "SELECT password FROM users WHERE userid='%u'", id); 187 | 188 | if (!ExecuteFirstQuery(db, res, query)) 189 | { 190 | delete res; 191 | return; 192 | } 193 | 194 | strncpy(out, res->GetStringFromRow(0).c_str(), out_len); 195 | out[out_len - 1] = '\0'; 196 | 197 | delete res; 198 | } 199 | 200 | unsigned int GetUserIDFromProfileID(CDatabase* db, unsigned int id, unsigned int* out) 201 | { 202 | CResultSet *res = new CResultSet(); 203 | char query[61]; 204 | unsigned int ret = 0; 205 | query[0] = 0; 206 | 207 | snprintf(query, sizeof(query), "SELECT userid FROM profiles WHERE profileid='%u'", id); 208 | 209 | if (!ExecuteFirstQuery(db, res, query)) 210 | { 211 | delete res; 212 | return false; 213 | } 214 | 215 | ret = res->GetUIntFromRow(0); 216 | *out = ret; 217 | 218 | delete res; 219 | return true; 220 | } 221 | 222 | int AssignSessionKeyFromProfileID(CDatabase* db, unsigned int profileid) 223 | { 224 | int ssk = 0; 225 | bool bx = true; 226 | char query[61]; 227 | query[0] = 0; 228 | 229 | while (bx) 230 | { 231 | ssk = RandInt(1, INT_MAX); 232 | snprintf(query, sizeof(query), "UPDATE profiles SET sesskey=%d WHERE profileid='%u'", ssk, profileid); 233 | 234 | if (mdk_only_run_query(db, query)) 235 | bx = false; 236 | } 237 | 238 | return ssk; 239 | } 240 | 241 | void FreeSessionKey(CDatabase* db, unsigned int profileid) 242 | { 243 | char query[61]; 244 | query[0] = 0; 245 | 246 | snprintf(query, sizeof(query), "UPDATE profiles SET sesskey=NULL WHERE profileid='%u'", profileid); 247 | 248 | mdk_only_run_query(db, query); 249 | } 250 | 251 | int GetPublicMaskFromProfileID(CDatabase* db, unsigned int pid) 252 | { 253 | CResultSet *res = new CResultSet(); 254 | std::string query = ""; 255 | int ret = 0; 256 | 257 | query = "SELECT publicmask FROM profiles WHERE profileid="; 258 | query += std::to_string(pid); 259 | 260 | if (!ExecuteFirstQuery(db, res, query)) 261 | { 262 | delete res; 263 | return ret; 264 | } 265 | 266 | ret = res->GetIntFromRow(0); 267 | 268 | delete res; 269 | return ret; 270 | } 271 | 272 | bool GetProfileInfo(CDatabase* db, unsigned int pid, GPIInfoCache *out, unsigned int *id_out) 273 | { 274 | #define resget(x) res->GetStringFromRow(x).c_str() 275 | 276 | CResultSet *res = new CResultSet(); 277 | std::string query = ""; 278 | 279 | query = "SELECT profiles.uniquenick, profiles.nick, profiles.firstname, profiles.lastname, profiles.latitude," //5 280 | " profiles.longitude, profiles.publicmask, profiles.userid, profiles.aim, profiles.picture," //9 281 | " profiles.occupationid, profiles.incomeid, profiles.industryid, profiles.marriedid, profiles.childcount," //14 282 | " profiles.interests1, profiles.ownership1, profiles.connectiontype, profiles.sex, profiles.zipcode," //19 283 | " profiles.countrycode, profiles.homepage, profiles.birthday, profiles.birthmonth, profiles.birthyear," //24 284 | " profiles.location, profiles.icq, users.email FROM profiles INNER JOIN users ON users.userid=profiles.userid WHERE profiles.profileid="; 285 | 286 | query += std::to_string(pid); 287 | 288 | if (!ExecuteFirstQuery(db, res, query)) 289 | { 290 | delete res; 291 | return false; 292 | } 293 | 294 | strncpy(out->uniquenick, resget(0), sizeof(out->uniquenick)); 295 | out->uniquenick[sizeof(out->uniquenick) - 1] = '\0'; 296 | strncpy(out->nick, resget(1), sizeof(out->nick)); 297 | out->nick[sizeof(out->nick) - 1] = '\0'; 298 | strncpy(out->firstname, resget(2), sizeof(out->firstname)); 299 | out->firstname[sizeof(out->firstname) - 1] = '\0'; 300 | strncpy(out->lastname, resget(3), sizeof(out->lastname)); 301 | out->lastname[sizeof(out->lastname) - 1] = '\0'; 302 | out->latitude = (float)res->GetDoubleFromRow(4); 303 | out->longitude = (float)res->GetDoubleFromRow(5); 304 | out->publicmask = res->GetIntFromRow(6); 305 | *id_out = res->GetUIntFromRow(7); 306 | strncpy(out->aimname, resget(8), sizeof(out->aimname)); 307 | out->aimname[sizeof(out->aimname) - 1] = '\0'; 308 | out->pic = res->GetIntFromRow(9); 309 | out->occupationid = res->GetIntFromRow(10); 310 | out->incomeid = res->GetIntFromRow(11); 311 | out->industryid = res->GetIntFromRow(12); 312 | out->marriedid = res->GetIntFromRow(13); 313 | out->childcount = res->GetIntFromRow(14); 314 | out->interests1 = res->GetIntFromRow(15); 315 | out->ownership1 = res->GetIntFromRow(16); 316 | out->conntypeid = res->GetIntFromRow(17); 317 | 318 | if (res->GetStringFromRow(18).compare("MALE") == 0) 319 | out->sex = GP_MALE; 320 | else if (res->GetStringFromRow(18).compare("FEMALE") == 0) 321 | out->sex = GP_FEMALE; 322 | else 323 | out->sex = GP_PAT; 324 | 325 | strncpy(out->zipcode, resget(19), sizeof(out->zipcode)); 326 | out->zipcode[sizeof(out->zipcode) - 1] = '\0'; 327 | strncpy(out->countrycode, resget(20), sizeof(out->countrycode)); 328 | out->countrycode[sizeof(out->countrycode) - 1] = '\0'; 329 | strncpy(out->homepage, resget(21), sizeof(out->homepage)); 330 | out->homepage[sizeof(out->homepage) - 1] = '\0'; 331 | out->birthday = res->GetIntFromRow(22); 332 | out->birthmonth = res->GetIntFromRow(23); 333 | out->birthyear = res->GetIntFromRow(24); 334 | strncpy(out->place, resget(25), sizeof(out->place)); 335 | out->place[sizeof(out->place) - 1] = '\0'; 336 | out->icquin = res->GetIntFromRow(26); 337 | strncpy(out->email, resget(27), sizeof(out->email)); 338 | out->email[sizeof(out->email) - 1] = '\0'; 339 | 340 | delete res; 341 | 342 | return true; 343 | } 344 | 345 | bool GetProfileIDFromAuthToken(CDatabase* db, const char *authtoken, unsigned int* out) 346 | { 347 | std::string query = ""; 348 | std::string _authtoken = authtoken; 349 | CResultSet *res = NULL; 350 | 351 | if (!mdk_escape_query_string(db, _authtoken)) 352 | return false; 353 | 354 | res = new CResultSet(); 355 | 356 | query = "SELECT profileid FROM authtoken WHERE token='"; 357 | query += _authtoken; 358 | query += "'"; 359 | 360 | if (!ExecuteFirstQuery(db, res, query)) 361 | { 362 | delete res; 363 | return false; 364 | } 365 | 366 | *out = res->GetUIntFromRow(0); 367 | 368 | delete res; 369 | return true; 370 | } 371 | 372 | int RegisterUser(CDatabase* db, const char* email, const char* nick, const char* pass, unsigned int* userid) 373 | { 374 | std::string query = "", _email = email, _nick = nick, _pass = pass; 375 | CResultSet* res = NULL; 376 | 377 | if (!mdk_escape_query_string(db, _email)) 378 | return false; 379 | 380 | if (!mdk_escape_query_string(db, _nick)) 381 | return false; 382 | 383 | if (!mdk_escape_query_string(db, _pass)) 384 | return false; 385 | 386 | query = "SELECT uniquenick FROM profiles WHERE uniquenick='"; 387 | query += _nick; 388 | query += "'"; 389 | 390 | res = new CResultSet(); 391 | 392 | if (!res->ExecuteQuery(db, query.c_str())) 393 | { 394 | delete res; 395 | return GP_NEWUSER; 396 | } 397 | 398 | if (res->GetTotalRows() > 0) 399 | { 400 | delete res; 401 | return GP_NEWUSER_UNIQUENICK_INUSE; 402 | } 403 | 404 | query = "SELECT email FROM users WHERE email='"; 405 | query += _email; 406 | query += "'"; 407 | 408 | if (!res->ExecuteQuery(db, query.c_str())) 409 | { 410 | delete res; 411 | return GP_NEWUSER; 412 | } 413 | 414 | if (res->GetTotalRows() > 0) 415 | { 416 | delete res; 417 | return GP_NEWUSER; 418 | } 419 | 420 | query = "INSERT INTO users(email, password, deleted, emailverified) VALUES ('"; 421 | query += _email; 422 | query += "', '"; 423 | query += _pass; 424 | query += "', 0, 1)"; 425 | 426 | if (!mdk_only_run_query(db, query)) 427 | { 428 | delete res; 429 | return GP_NEWUSER; 430 | } 431 | 432 | query = "SELECT userid FROM users WHERE email='"; 433 | query += _email; 434 | query += "'"; 435 | 436 | if (!ExecuteFirstQuery(db, res, query)) 437 | { 438 | delete res; 439 | return GP_NEWUSER; 440 | } 441 | 442 | query = "INSERT INTO profiles(userid, uniquenick, nick) VALUES ("; 443 | query += std::to_string(res->GetUIntFromRow(0)); 444 | query += ", '"; 445 | query += _nick; 446 | query += "', '"; 447 | query += _nick; 448 | query += "')"; 449 | 450 | if (!mdk_only_run_query(db, query)) 451 | { 452 | delete res; 453 | return GP_NEWUSER; 454 | } 455 | 456 | query = "SELECT profileid FROM profiles WHERE uniquenick='"; 457 | query += _nick; 458 | query += "'"; 459 | 460 | if (!ExecuteFirstQuery(db, res, query)) 461 | { 462 | delete res; 463 | return GP_NEWUSER; 464 | } 465 | 466 | *userid = res->GetUIntFromRow(0); 467 | 468 | delete res; 469 | return -1; 470 | } -------------------------------------------------------------------------------- /common/Helper_Random.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 Luigi Auriemma 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | http://www.gnu.org/licenses/gpl-2.0.txt 19 | */ 20 | #include "Helper.h" 21 | 22 | // Cross platform random number generator 23 | #define RANa 16807 // multiplier 24 | #define LONGRAND_MAX 2147483647L // 2**31 - 1 25 | 26 | static long randomnum = 1; 27 | 28 | static long nextlongrand(long seed) 29 | { 30 | unsigned long lo, hi; 31 | lo = RANa * (unsigned long)(seed & 0xFFFF); 32 | hi = RANa * ((unsigned long)seed >> 16); 33 | lo += (hi & 0x7FFF) << 16; 34 | 35 | if (lo > LONGRAND_MAX) 36 | { 37 | lo &= LONGRAND_MAX; 38 | ++lo; 39 | } 40 | lo += hi >> 15; 41 | 42 | if (lo > LONGRAND_MAX) 43 | { 44 | lo &= LONGRAND_MAX; 45 | ++lo; 46 | } 47 | 48 | return(long)lo; 49 | } 50 | 51 | // return next random long 52 | static long longrand(void) 53 | { 54 | randomnum = nextlongrand(randomnum); 55 | return randomnum; 56 | } 57 | 58 | // to seed it 59 | void RandSeed(unsigned long seed) 60 | { 61 | // nonzero seed 62 | randomnum = seed ? (long)(seed & LONGRAND_MAX) : 1; 63 | } 64 | 65 | int RandInt(int low, int high) 66 | { 67 | unsigned int range = (unsigned int)high - low; 68 | int num; 69 | 70 | if (range == 0) 71 | return (low); // Prevent divide by zero 72 | 73 | num = (int)(longrand() % range); 74 | 75 | return(num + low); 76 | } 77 | -------------------------------------------------------------------------------- /common/TemplateStringServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Foobar is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with Foobar. If not, see . 16 | */ 17 | #include "TemplateStringServer.h" 18 | 19 | #include "Helper.h" 20 | 21 | #include 22 | 23 | CTemplateStringServer::CTemplateStringServer(int defaultport, bool udp) : CThreadServer(defaultport, udp) {} 24 | CTemplateStringServer::~CTemplateStringServer() {} 25 | 26 | void CTemplateStringServer::OnTCPRead(mdk_socket stream, const char *data, ssize_t size) 27 | { 28 | bool bC = true; 29 | char *buffer2 = NULL; 30 | 31 | if (size < 8) 32 | return; 33 | 34 | buffer2 = (char*)malloc(sizeof(char)*(size+1)); 35 | strncpy(buffer2, data, size); 36 | buffer2[size] = 0; 37 | 38 | /* Check if the buffer is valid */ 39 | if (!is_gs_valid(buffer2)) 40 | return; 41 | 42 | /* Loop to handle multiple request in the same buffer (it happends somehow) */ 43 | while (bC) 44 | { 45 | char *find_str = NULL; 46 | char *the_string = NULL; 47 | 48 | size_t pos = 0; 49 | 50 | /* Check if the buffer is NULL */ 51 | if (buffer2[0] == '\0') 52 | bC = false; 53 | else 54 | { 55 | /* Find the last part of a buffer */ 56 | find_str = strstr(buffer2, "final\\"); 57 | 58 | if (find_str == NULL) 59 | bC = false; /* Invalid request */ 60 | else 61 | { 62 | char type[128]; 63 | 64 | type[0] = 0; 65 | 66 | size_t rq_pos = 0; 67 | 68 | pos = find_str - buffer2; 69 | 70 | /* Allocate the string where we take the part our buffer */ 71 | the_string = (char *)malloc(sizeof(char) * (pos+1)); 72 | 73 | /* Copy the request into the string */ 74 | strncpy(the_string, buffer2, pos); 75 | the_string[pos] = '\0'; 76 | 77 | /* Get the first request "x//" */ 78 | rq_pos = get_gs_req(the_string, type, sizeof(type)); 79 | if (rq_pos == -1) 80 | { 81 | /* Invalid request */ 82 | Close(stream); 83 | bC = false; 84 | } 85 | else 86 | { 87 | /* Send it to the master handler */ 88 | if (!HandleRequest(stream, type, &the_string[rq_pos], pos - rq_pos)) 89 | { 90 | /* It wanted to close the socket, ok */ 91 | Close(stream); 92 | bC = false; 93 | } 94 | } 95 | 96 | 97 | free(the_string); /* Free allocated memory */ 98 | } 99 | 100 | /* If we can continue, continue to control the buffer */ 101 | if (bC) 102 | buffer2 = &buffer2[pos + 6]; 103 | } 104 | } 105 | } 106 | 107 | // Virtual functions 108 | bool CTemplateStringServer::OnTCPNewConnection(mdk_socket, int) { return true; } 109 | bool CTemplateStringServer::HandleRequest(mdk_socket, const char *, const char *, int) { return true; } 110 | -------------------------------------------------------------------------------- /common/TemplateStringServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Foobar is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with Foobar. If not, see . 16 | */ 17 | #ifndef RETROSPYCOMMON_STRINGSERVER_H 18 | #define RETROSPYCOMMON_STRINGSERVER_H 19 | 20 | #include 21 | 22 | /* 23 | This class is a Server that handle generic 24 | string packets (like GPSP requests) 25 | */ 26 | class CTemplateStringServer : public CThreadServer 27 | { 28 | public: 29 | CTemplateStringServer(int defaultport, bool udp); 30 | ~CTemplateStringServer(); 31 | 32 | /* See CServer::OnRead */ 33 | void OnTCPRead(mdk_socket stream, const char *data, ssize_t size); 34 | void OnUDPRead(mdk_socket stream, const struct sockaddr* addr, const char*data, ssize_t size) {} 35 | 36 | /* See CServer::OnNewConnection */ 37 | virtual bool OnTCPNewConnection(mdk_socket stream, int status) = 0; 38 | 39 | /* 40 | Function: HandleRequest 41 | Description: Called when a request is received 42 | Return: true if you want to keep the connection, otherwise false 43 | Parameters: 44 | stream => A pointer to the client 45 | req => The request 46 | buf => The content of the request 47 | size => The length of the content 48 | */ 49 | virtual bool HandleRequest(mdk_socket stream, const char *req, const char *buf, int size); 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /common/chc_endian.cpp: -------------------------------------------------------------------------------- 1 | /* chc_endian by Andrew "CHCNiZ" Learn 2 | * Copyright (C) 2009 Andrew Learn 3 | * 4 | * chc_endian is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * chc_endian is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with chc_endian. If not, see . 16 | */ 17 | #include "chc_endian.h" 18 | 19 | //now obviously madness like this isn't used often(who would need invert_bytes for example) a lot of its just for fun and no cpu i've heard of uses such a byte order, but its still included into this header 20 | uint32_t little_to_middle(uint32_t x) { //0xABCDEF02 becomes 0xCDAB02EF this is used for converting from middle endian(ARM CPU's/PDP-11) to little endian 21 | return x<<8&0xff000000|x>>8&0xff0000|(x&0x0000ff00)>>8|(x&0x000000ff)<<8; 22 | } 23 | 24 | uint32_t reverse_endian32(uint32_t x) { //little to big or vice versa 25 | return (x<<24|(x<<8&0x00ff0000)|x>>8&0x0000ff00|x>>24&0x000000ff); 26 | } 27 | 28 | uint32_t invert_bytes(uint32_t x) { //0xABCDEF02 becomes 0xBADCFE20 29 | return ((x&0x0f000000)<<4|(x&0xf0000000)>>4|(x&0x00f00000)>>4|(x&0x000f0000)<<4|(x&0x0000f000)>>4|(x&0x00000f00)<<4|(x&0x000000f0)>>4|(x&0x0000000f)<<4); 30 | } 31 | 32 | uint32_t rev_bendian32(uint32_t x) { //0xABCDEF02 becomes 0x20FEDCAB 33 | return ((x&0x0f0000)<<4|(x&0xf00000)>>4)>>8|((x&0x0f)<<4|(x&0xf0)>>4)<<24|((x&0x0f00)<<4|(x&0xf000)>>4)<<8|((x&0x0f000000)<<4|(x&0xf0000000)>>4)>>24; 34 | } 35 | 36 | uint16_t reverse_endian16(uint16_t x) { //little to big or vice versa 37 | return (x&0xff00)>>8|(x&0x00ff)<<8; 38 | } 39 | 40 | uint16_t invert_inner16(uint16_t x) {//0xABCD becomes 0xACBD 41 | return x&0xf00f|(x&0x0f00)>>4|(x&0x00f0)<<4; 42 | } 43 | 44 | uint16_t invert_outer16(uint16_t x) { //0xABCD becomes 0xDBCA 45 | return (x&0x000f)<<12|x&0x0ff0|(x&0xf000)>>12; 46 | } 47 | 48 | uint16_t flipbyte16(uint16_t x) { //0xABCD becomes 0xBADC 49 | return (x&0x0f00)<<4|(x&0xf000)>>4|(x&0x000f)<<4|(x&0x00f0)>>4; 50 | } 51 | 52 | uint8_t flipbyte(uint8_t x) { //0xAB becomes 0xBA 53 | return x<<4&0xf0|(x>>4)&0x0f; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /common/chc_endian.h: -------------------------------------------------------------------------------- 1 | /* chc_endian by Andrew "CHCNiZ" Learn 2 | * Copyright (C) 2009 Andrew Learn 3 | * 4 | * chc_endian is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * chc_endian is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with chc_endian. If not, see . 16 | */ 17 | #ifndef _CHC_ENDIAN_INC 18 | #define _CHC_ENDIAN_INC 19 | 20 | // Changed to msstdint 21 | #include 22 | 23 | //now obviously madness like this isn't used often(who would need invert_bytes for example) a lot of its just for fun and no cpu i've heard of uses such a byte order, but its still included into this header 24 | uint32_t little_to_middle(uint32_t x); 25 | uint32_t reverse_endian32(uint32_t x); 26 | uint32_t invert_bytes(uint32_t x); 27 | uint32_t rev_bendian32(uint32_t x); 28 | uint16_t reverse_endian16(uint16_t x); 29 | uint16_t invert_inner16(uint16_t x); 30 | uint16_t invert_outer16(uint16_t x); 31 | uint16_t flipbyte16(uint16_t x); 32 | uint8_t flipbyte(uint8_t x); 33 | 34 | #endif -------------------------------------------------------------------------------- /common/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * RFC 1321 compliant MD5 implementation 3 | * 4 | * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine 5 | * 6 | * Copyright (C) 2009 Paul Bakker 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | /* 23 | * The MD5 algorithm was designed by Ron Rivest in 1991. 24 | * 25 | * http://www.ietf.org/rfc/rfc1321.txt 26 | */ 27 | 28 | //#include "polarssl/config.h" 29 | #include "md5.h" 30 | #define POLARSSL_MD5_C 31 | #if defined(POLARSSL_MD5_C) 32 | 33 | //#include "polarssl/md5.h" 34 | 35 | #include 36 | #include 37 | 38 | #ifndef _WIN32 39 | void fopen_s(FILE**fp, const char *path, const char *mode) { *fp = fopen(path, mode); } 40 | #endif 41 | 42 | /* 43 | * 32-bit integer manipulation macros (little endian) 44 | */ 45 | #ifndef GET_ULONG_LE 46 | #define GET_ULONG_LE(n,b,i) \ 47 | { \ 48 | (n) = ( (unsigned long) (b)[(i) ] ) \ 49 | | ( (unsigned long) (b)[(i) + 1] << 8 ) \ 50 | | ( (unsigned long) (b)[(i) + 2] << 16 ) \ 51 | | ( (unsigned long) (b)[(i) + 3] << 24 ); \ 52 | } 53 | #endif 54 | 55 | #ifndef PUT_ULONG_LE 56 | #define PUT_ULONG_LE(n,b,i) \ 57 | { \ 58 | (b)[(i) ] = (unsigned char) ( (n) ); \ 59 | (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ 60 | (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ 61 | (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ 62 | } 63 | #endif 64 | 65 | /* 66 | * MD5 context setup 67 | */ 68 | void md5_starts( md5_context *ctx ) 69 | { 70 | ctx->total[0] = 0; 71 | ctx->total[1] = 0; 72 | 73 | ctx->state[0] = 0x67452301; 74 | ctx->state[1] = 0xEFCDAB89; 75 | ctx->state[2] = 0x98BADCFE; 76 | ctx->state[3] = 0x10325476; 77 | } 78 | 79 | static void md5_process( md5_context *ctx, unsigned char data[64] ) 80 | { 81 | unsigned long X[16], A, B, C, D; 82 | 83 | GET_ULONG_LE( X[ 0], data, 0 ); 84 | GET_ULONG_LE( X[ 1], data, 4 ); 85 | GET_ULONG_LE( X[ 2], data, 8 ); 86 | GET_ULONG_LE( X[ 3], data, 12 ); 87 | GET_ULONG_LE( X[ 4], data, 16 ); 88 | GET_ULONG_LE( X[ 5], data, 20 ); 89 | GET_ULONG_LE( X[ 6], data, 24 ); 90 | GET_ULONG_LE( X[ 7], data, 28 ); 91 | GET_ULONG_LE( X[ 8], data, 32 ); 92 | GET_ULONG_LE( X[ 9], data, 36 ); 93 | GET_ULONG_LE( X[10], data, 40 ); 94 | GET_ULONG_LE( X[11], data, 44 ); 95 | GET_ULONG_LE( X[12], data, 48 ); 96 | GET_ULONG_LE( X[13], data, 52 ); 97 | GET_ULONG_LE( X[14], data, 56 ); 98 | GET_ULONG_LE( X[15], data, 60 ); 99 | 100 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) 101 | 102 | #define P(a,b,c,d,k,s,t) \ 103 | { \ 104 | a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ 105 | } 106 | 107 | A = ctx->state[0]; 108 | B = ctx->state[1]; 109 | C = ctx->state[2]; 110 | D = ctx->state[3]; 111 | 112 | #define F(x,y,z) (z ^ (x & (y ^ z))) 113 | 114 | P( A, B, C, D, 0, 7, 0xD76AA478 ); 115 | P( D, A, B, C, 1, 12, 0xE8C7B756 ); 116 | P( C, D, A, B, 2, 17, 0x242070DB ); 117 | P( B, C, D, A, 3, 22, 0xC1BDCEEE ); 118 | P( A, B, C, D, 4, 7, 0xF57C0FAF ); 119 | P( D, A, B, C, 5, 12, 0x4787C62A ); 120 | P( C, D, A, B, 6, 17, 0xA8304613 ); 121 | P( B, C, D, A, 7, 22, 0xFD469501 ); 122 | P( A, B, C, D, 8, 7, 0x698098D8 ); 123 | P( D, A, B, C, 9, 12, 0x8B44F7AF ); 124 | P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); 125 | P( B, C, D, A, 11, 22, 0x895CD7BE ); 126 | P( A, B, C, D, 12, 7, 0x6B901122 ); 127 | P( D, A, B, C, 13, 12, 0xFD987193 ); 128 | P( C, D, A, B, 14, 17, 0xA679438E ); 129 | P( B, C, D, A, 15, 22, 0x49B40821 ); 130 | 131 | #undef F 132 | 133 | #define F(x,y,z) (y ^ (z & (x ^ y))) 134 | 135 | P( A, B, C, D, 1, 5, 0xF61E2562 ); 136 | P( D, A, B, C, 6, 9, 0xC040B340 ); 137 | P( C, D, A, B, 11, 14, 0x265E5A51 ); 138 | P( B, C, D, A, 0, 20, 0xE9B6C7AA ); 139 | P( A, B, C, D, 5, 5, 0xD62F105D ); 140 | P( D, A, B, C, 10, 9, 0x02441453 ); 141 | P( C, D, A, B, 15, 14, 0xD8A1E681 ); 142 | P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); 143 | P( A, B, C, D, 9, 5, 0x21E1CDE6 ); 144 | P( D, A, B, C, 14, 9, 0xC33707D6 ); 145 | P( C, D, A, B, 3, 14, 0xF4D50D87 ); 146 | P( B, C, D, A, 8, 20, 0x455A14ED ); 147 | P( A, B, C, D, 13, 5, 0xA9E3E905 ); 148 | P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); 149 | P( C, D, A, B, 7, 14, 0x676F02D9 ); 150 | P( B, C, D, A, 12, 20, 0x8D2A4C8A ); 151 | 152 | #undef F 153 | 154 | #define F(x,y,z) (x ^ y ^ z) 155 | 156 | P( A, B, C, D, 5, 4, 0xFFFA3942 ); 157 | P( D, A, B, C, 8, 11, 0x8771F681 ); 158 | P( C, D, A, B, 11, 16, 0x6D9D6122 ); 159 | P( B, C, D, A, 14, 23, 0xFDE5380C ); 160 | P( A, B, C, D, 1, 4, 0xA4BEEA44 ); 161 | P( D, A, B, C, 4, 11, 0x4BDECFA9 ); 162 | P( C, D, A, B, 7, 16, 0xF6BB4B60 ); 163 | P( B, C, D, A, 10, 23, 0xBEBFBC70 ); 164 | P( A, B, C, D, 13, 4, 0x289B7EC6 ); 165 | P( D, A, B, C, 0, 11, 0xEAA127FA ); 166 | P( C, D, A, B, 3, 16, 0xD4EF3085 ); 167 | P( B, C, D, A, 6, 23, 0x04881D05 ); 168 | P( A, B, C, D, 9, 4, 0xD9D4D039 ); 169 | P( D, A, B, C, 12, 11, 0xE6DB99E5 ); 170 | P( C, D, A, B, 15, 16, 0x1FA27CF8 ); 171 | P( B, C, D, A, 2, 23, 0xC4AC5665 ); 172 | 173 | #undef F 174 | 175 | #define F(x,y,z) (y ^ (x | ~z)) 176 | 177 | P( A, B, C, D, 0, 6, 0xF4292244 ); 178 | P( D, A, B, C, 7, 10, 0x432AFF97 ); 179 | P( C, D, A, B, 14, 15, 0xAB9423A7 ); 180 | P( B, C, D, A, 5, 21, 0xFC93A039 ); 181 | P( A, B, C, D, 12, 6, 0x655B59C3 ); 182 | P( D, A, B, C, 3, 10, 0x8F0CCC92 ); 183 | P( C, D, A, B, 10, 15, 0xFFEFF47D ); 184 | P( B, C, D, A, 1, 21, 0x85845DD1 ); 185 | P( A, B, C, D, 8, 6, 0x6FA87E4F ); 186 | P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); 187 | P( C, D, A, B, 6, 15, 0xA3014314 ); 188 | P( B, C, D, A, 13, 21, 0x4E0811A1 ); 189 | P( A, B, C, D, 4, 6, 0xF7537E82 ); 190 | P( D, A, B, C, 11, 10, 0xBD3AF235 ); 191 | P( C, D, A, B, 2, 15, 0x2AD7D2BB ); 192 | P( B, C, D, A, 9, 21, 0xEB86D391 ); 193 | 194 | #undef F 195 | 196 | ctx->state[0] += A; 197 | ctx->state[1] += B; 198 | ctx->state[2] += C; 199 | ctx->state[3] += D; 200 | } 201 | 202 | /* 203 | * MD5 process buffer 204 | */ 205 | void md5_update( md5_context *ctx, unsigned char *input, int ilen ) 206 | { 207 | int fill; 208 | unsigned long left; 209 | 210 | if( ilen <= 0 ) 211 | return; 212 | 213 | left = ctx->total[0] & 0x3F; 214 | fill = 64 - left; 215 | 216 | ctx->total[0] += ilen; 217 | ctx->total[0] &= 0xFFFFFFFF; 218 | 219 | if( ctx->total[0] < (unsigned long) ilen ) 220 | ctx->total[1]++; 221 | 222 | if( left && ilen >= fill ) 223 | { 224 | memcpy( (void *) (ctx->buffer + left), 225 | (void *) input, fill ); 226 | md5_process( ctx, ctx->buffer ); 227 | input += fill; 228 | ilen -= fill; 229 | left = 0; 230 | } 231 | 232 | while( ilen >= 64 ) 233 | { 234 | md5_process( ctx, input ); 235 | input += 64; 236 | ilen -= 64; 237 | } 238 | 239 | if( ilen > 0 ) 240 | { 241 | memcpy( (void *) (ctx->buffer + left), 242 | (void *) input, ilen ); 243 | } 244 | } 245 | 246 | static const unsigned char md5_padding[64] = 247 | { 248 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 252 | }; 253 | 254 | /* 255 | * MD5 final digest 256 | */ 257 | void md5_finish( md5_context *ctx, unsigned char output[16] ) 258 | { 259 | unsigned long last, padn; 260 | unsigned long high, low; 261 | unsigned char msglen[8]; 262 | 263 | high = ( ctx->total[0] >> 29 ) 264 | | ( ctx->total[1] << 3 ); 265 | low = ( ctx->total[0] << 3 ); 266 | 267 | PUT_ULONG_LE( low, msglen, 0 ); 268 | PUT_ULONG_LE( high, msglen, 4 ); 269 | 270 | last = ctx->total[0] & 0x3F; 271 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); 272 | 273 | md5_update( ctx, (unsigned char *) md5_padding, padn ); 274 | md5_update( ctx, msglen, 8 ); 275 | 276 | PUT_ULONG_LE( ctx->state[0], output, 0 ); 277 | PUT_ULONG_LE( ctx->state[1], output, 4 ); 278 | PUT_ULONG_LE( ctx->state[2], output, 8 ); 279 | PUT_ULONG_LE( ctx->state[3], output, 12 ); 280 | } 281 | 282 | /* 283 | * output = MD5( input buffer ) 284 | */ 285 | void md5( unsigned char *input, int ilen, unsigned char output[16] ) 286 | { 287 | md5_context ctx; 288 | 289 | md5_starts( &ctx ); 290 | md5_update( &ctx, input, ilen ); 291 | md5_finish( &ctx, output ); 292 | 293 | memset( &ctx, 0, sizeof( md5_context ) ); 294 | } 295 | 296 | /* 297 | * output = MD5( file contents ) 298 | */ 299 | int md5_file( char *path, unsigned char output[16] ) 300 | { 301 | // Function changed to support fopen_s 302 | FILE *f = NULL; 303 | size_t n; 304 | md5_context ctx; 305 | unsigned char buf[1024]; 306 | 307 | fopen_s(&f, path, "rb"); 308 | 309 | if (f == NULL) 310 | return( 1 ); 311 | 312 | md5_starts( &ctx ); 313 | 314 | while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) 315 | md5_update( &ctx, buf, (int) n ); 316 | 317 | md5_finish( &ctx, output ); 318 | 319 | memset( &ctx, 0, sizeof( md5_context ) ); 320 | 321 | if( ferror( f ) != 0 ) 322 | { 323 | fclose( f ); 324 | return( 2 ); 325 | } 326 | 327 | fclose( f ); 328 | return( 0 ); 329 | } 330 | 331 | /* 332 | * MD5 HMAC context setup 333 | */ 334 | void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen ) 335 | { 336 | int i; 337 | unsigned char sum[16]; 338 | 339 | if( keylen > 64 ) 340 | { 341 | md5( key, keylen, sum ); 342 | keylen = 16; 343 | key = sum; 344 | } 345 | 346 | memset( ctx->ipad, 0x36, 64 ); 347 | memset( ctx->opad, 0x5C, 64 ); 348 | 349 | for( i = 0; i < keylen; i++ ) 350 | { 351 | ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); 352 | ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); 353 | } 354 | 355 | md5_starts( ctx ); 356 | md5_update( ctx, ctx->ipad, 64 ); 357 | 358 | memset( sum, 0, sizeof( sum ) ); 359 | } 360 | 361 | /* 362 | * MD5 HMAC process buffer 363 | */ 364 | void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen ) 365 | { 366 | md5_update( ctx, input, ilen ); 367 | } 368 | 369 | /* 370 | * MD5 HMAC final digest 371 | */ 372 | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ) 373 | { 374 | unsigned char tmpbuf[16]; 375 | 376 | md5_finish( ctx, tmpbuf ); 377 | md5_starts( ctx ); 378 | md5_update( ctx, ctx->opad, 64 ); 379 | md5_update( ctx, tmpbuf, 16 ); 380 | md5_finish( ctx, output ); 381 | 382 | memset( tmpbuf, 0, sizeof( tmpbuf ) ); 383 | } 384 | 385 | /* 386 | * output = HMAC-MD5( hmac key, input buffer ) 387 | */ 388 | void md5_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen, 389 | unsigned char output[16] ) 390 | { 391 | md5_context ctx; 392 | 393 | md5_hmac_starts( &ctx, key, keylen ); 394 | md5_hmac_update( &ctx, input, ilen ); 395 | md5_hmac_finish( &ctx, output ); 396 | 397 | memset( &ctx, 0, sizeof( md5_context ) ); 398 | } 399 | 400 | #if defined(POLARSSL_SELF_TEST) 401 | /* 402 | * RFC 1321 test vectors 403 | */ 404 | static unsigned char md5_test_buf[7][81] = 405 | { 406 | { "" }, 407 | { "a" }, 408 | { "abc" }, 409 | { "message digest" }, 410 | { "abcdefghijklmnopqrstuvwxyz" }, 411 | { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, 412 | { "12345678901234567890123456789012345678901234567890123456789012" \ 413 | "345678901234567890" } 414 | }; 415 | 416 | static const int md5_test_buflen[7] = 417 | { 418 | 0, 1, 3, 14, 26, 62, 80 419 | }; 420 | 421 | static const unsigned char md5_test_sum[7][16] = 422 | { 423 | { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, 424 | 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, 425 | { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, 426 | 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, 427 | { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, 428 | 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, 429 | { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, 430 | 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, 431 | { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, 432 | 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, 433 | { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, 434 | 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, 435 | { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, 436 | 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } 437 | }; 438 | 439 | /* 440 | * RFC 2202 test vectors 441 | */ 442 | static unsigned char md5_hmac_test_key[7][26] = 443 | { 444 | { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" }, 445 | { "Jefe" }, 446 | { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" }, 447 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" 448 | "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, 449 | { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" }, 450 | { "" }, /* 0xAA 80 times */ 451 | { "" } 452 | }; 453 | 454 | static const int md5_hmac_test_keylen[7] = 455 | { 456 | 16, 4, 16, 25, 16, 80, 80 457 | }; 458 | 459 | static unsigned char md5_hmac_test_buf[7][74] = 460 | { 461 | { "Hi There" }, 462 | { "what do ya want for nothing?" }, 463 | { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 464 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 465 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 466 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 467 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, 468 | { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 469 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 470 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 471 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 472 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, 473 | { "Test With Truncation" }, 474 | { "Test Using Larger Than Block-Size Key - Hash Key First" }, 475 | { "Test Using Larger Than Block-Size Key and Larger" 476 | " Than One Block-Size Data" } 477 | }; 478 | 479 | static const int md5_hmac_test_buflen[7] = 480 | { 481 | 8, 28, 50, 50, 20, 54, 73 482 | }; 483 | 484 | static const unsigned char md5_hmac_test_sum[7][16] = 485 | { 486 | { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C, 487 | 0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D }, 488 | { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03, 489 | 0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 }, 490 | { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88, 491 | 0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 }, 492 | { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA, 493 | 0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 }, 494 | { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00, 495 | 0xF9, 0xBA, 0xB9, 0x95 }, 496 | { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F, 497 | 0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD }, 498 | { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE, 499 | 0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E } 500 | }; 501 | 502 | /* 503 | * Checkup routine 504 | */ 505 | int md5_self_test( int verbose ) 506 | { 507 | int i, buflen; 508 | unsigned char buf[1024]; 509 | unsigned char md5sum[16]; 510 | md5_context ctx; 511 | 512 | for( i = 0; i < 7; i++ ) 513 | { 514 | if( verbose != 0 ) 515 | printf( " MD5 test #%d: ", i + 1 ); 516 | 517 | md5( md5_test_buf[i], md5_test_buflen[i], md5sum ); 518 | 519 | if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) 520 | { 521 | if( verbose != 0 ) 522 | printf( "failed\n" ); 523 | 524 | return( 1 ); 525 | } 526 | 527 | if( verbose != 0 ) 528 | printf( "passed\n" ); 529 | } 530 | 531 | if( verbose != 0 ) 532 | printf( "\n" ); 533 | 534 | for( i = 0; i < 7; i++ ) 535 | { 536 | if( verbose != 0 ) 537 | printf( " HMAC-MD5 test #%d: ", i + 1 ); 538 | 539 | if( i == 5 || i == 6 ) 540 | { 541 | memset( buf, '\xAA', buflen = 80 ); 542 | md5_hmac_starts( &ctx, buf, buflen ); 543 | } 544 | else 545 | md5_hmac_starts( &ctx, md5_hmac_test_key[i], 546 | md5_hmac_test_keylen[i] ); 547 | 548 | md5_hmac_update( &ctx, md5_hmac_test_buf[i], 549 | md5_hmac_test_buflen[i] ); 550 | 551 | md5_hmac_finish( &ctx, md5sum ); 552 | 553 | buflen = ( i == 4 ) ? 12 : 16; 554 | 555 | if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 ) 556 | { 557 | if( verbose != 0 ) 558 | printf( "failed\n" ); 559 | 560 | return( 1 ); 561 | } 562 | 563 | if( verbose != 0 ) 564 | printf( "passed\n" ); 565 | } 566 | 567 | if( verbose != 0 ) 568 | printf( "\n" ); 569 | 570 | return( 0 ); 571 | } 572 | 573 | #endif 574 | 575 | #endif 576 | -------------------------------------------------------------------------------- /common/md5.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file md5.h 3 | * 4 | * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine 5 | * 6 | * Copyright (C) 2009 Paul Bakker 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | #ifndef POLARSSL_MD5_H 23 | #define POLARSSL_MD5_H 24 | 25 | /** 26 | * \brief MD5 context structure 27 | */ 28 | typedef struct 29 | { 30 | unsigned long total[2]; /*!< number of bytes processed */ 31 | unsigned long state[4]; /*!< intermediate digest state */ 32 | unsigned char buffer[64]; /*!< data block being processed */ 33 | 34 | unsigned char ipad[64]; /*!< HMAC: inner padding */ 35 | unsigned char opad[64]; /*!< HMAC: outer padding */ 36 | } 37 | md5_context; 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /** 44 | * \brief MD5 context setup 45 | * 46 | * \param ctx context to be initialized 47 | */ 48 | void md5_starts( md5_context *ctx ); 49 | 50 | /** 51 | * \brief MD5 process buffer 52 | * 53 | * \param ctx MD5 context 54 | * \param input buffer holding the data 55 | * \param ilen length of the input data 56 | */ 57 | void md5_update( md5_context *ctx, unsigned char *input, int ilen ); 58 | 59 | /** 60 | * \brief MD5 final digest 61 | * 62 | * \param ctx MD5 context 63 | * \param output MD5 checksum result 64 | */ 65 | void md5_finish( md5_context *ctx, unsigned char output[16] ); 66 | 67 | /** 68 | * \brief Output = MD5( input buffer ) 69 | * 70 | * \param input buffer holding the data 71 | * \param ilen length of the input data 72 | * \param output MD5 checksum result 73 | */ 74 | void md5( unsigned char *input, int ilen, unsigned char output[16] ); 75 | 76 | /** 77 | * \brief Output = MD5( file contents ) 78 | * 79 | * \param path input file name 80 | * \param output MD5 checksum result 81 | * 82 | * \return 0 if successful, 1 if fopen failed, 83 | * or 2 if fread failed 84 | */ 85 | int md5_file( char *path, unsigned char output[16] ); 86 | 87 | /** 88 | * \brief MD5 HMAC context setup 89 | * 90 | * \param ctx HMAC context to be initialized 91 | * \param key HMAC secret key 92 | * \param keylen length of the HMAC key 93 | */ 94 | void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen ); 95 | 96 | /** 97 | * \brief MD5 HMAC process buffer 98 | * 99 | * \param ctx HMAC context 100 | * \param input buffer holding the data 101 | * \param ilen length of the input data 102 | */ 103 | void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen ); 104 | 105 | /** 106 | * \brief MD5 HMAC final digest 107 | * 108 | * \param ctx HMAC context 109 | * \param output MD5 HMAC checksum result 110 | */ 111 | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ); 112 | 113 | /** 114 | * \brief Output = HMAC-MD5( hmac key, input buffer ) 115 | * 116 | * \param key HMAC secret key 117 | * \param keylen length of the HMAC key 118 | * \param input buffer holding the data 119 | * \param ilen length of the input data 120 | * \param output HMAC-MD5 result 121 | */ 122 | void md5_hmac( unsigned char *key, int keylen, 123 | unsigned char *input, int ilen, 124 | unsigned char output[16] ); 125 | 126 | /** 127 | * \brief Checkup routine 128 | * 129 | * \return 0 if successful, or 1 if the test failed 130 | */ 131 | int md5_self_test( int verbose ); 132 | 133 | #ifdef __cplusplus 134 | } 135 | #endif 136 | 137 | #endif /* md5.h */ 138 | -------------------------------------------------------------------------------- /natneg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | ${CMAKE_CURRENT_LIST_DIR}/NNServer.cpp 3 | ${CMAKE_CURRENT_LIST_DIR}/NNServer.h 4 | ${CMAKE_CURRENT_LIST_DIR}/ClientManager.h 5 | ${CMAKE_CURRENT_LIST_DIR}/NNTypes.h 6 | ${CMAKE_CURRENT_LIST_DIR}/ClientManager.cpp 7 | ${CMAKE_CURRENT_LIST_DIR}/Client.h 8 | ${CMAKE_CURRENT_LIST_DIR}/Client.cpp 9 | ) 10 | 11 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../common") 12 | 13 | add_library(NatNeg SHARED ${SOURCES}) 14 | target_link_libraries(NatNeg RetroSpyCommon) 15 | -------------------------------------------------------------------------------- /natneg/Client.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "Client.h" 18 | 19 | #include "ClientManager.h" 20 | 21 | #include 22 | 23 | #include "NNServer.h" 24 | 25 | #include 26 | 27 | #ifdef _WIN32 28 | #define close closesocket 29 | #endif 30 | 31 | static unsigned char NNMagicData[] = {NN_MAGIC_0, NN_MAGIC_1, NN_MAGIC_2, NN_MAGIC_3, NN_MAGIC_4, NN_MAGIC_5}; 32 | 33 | CClient::~CClient() 34 | { 35 | Disconnect(); 36 | } 37 | 38 | CClient::CClient(mdk_socket stream, const struct sockaddr_in* addr, CDatabase* db) 39 | { 40 | m_stream = stream; 41 | m_dbConnect = db; 42 | memcpy(&m_addr, addr, sizeof(struct sockaddr_in)); 43 | memcpy(&m_punching, addr, sizeof(struct sockaddr_in)); 44 | 45 | #ifdef _WIN32 46 | inet_ntop(AF_INET, (const VOID*)&(addr->sin_addr), m_ip, INET_ADDRSTRLEN); 47 | #else 48 | inet_ntop(AF_INET, &(addr->sin_addr), m_ip, INET_ADDRSTRLEN); 49 | #endif 50 | m_port = addr->sin_port; 51 | 52 | m_lastpacket = 0; 53 | m_ack = false; 54 | m_lastpacket = time(NULL); 55 | m_version = 0; 56 | m_clientindex = 0; 57 | m_init = false; 58 | m_connectTime = time(NULL); 59 | m_connected = false; 60 | } 61 | 62 | void CClient::Disconnect() 63 | { 64 | m_connected = false; 65 | } 66 | 67 | bool CClient::Handle(const char *buf, ssize_t len) 68 | { 69 | NatNegPacket *packet = (NatNegPacket*)buf; 70 | if (memcmp(packet->magic, NNMagicData, NATNEG_MAGIC_LEN) != 0) 71 | return false; 72 | 73 | m_lastpacket = time(NULL); 74 | 75 | switch(packet->packettype) 76 | { 77 | case NN_INIT: 78 | return HandleInitPacket(packet); 79 | case NN_ADDRESS_CHECK: 80 | return HandleAddressCheck(packet); 81 | case NN_NATIFY_REQUEST: 82 | return HandleNatifyRequest(packet); 83 | case NN_CONNECT_ACK: 84 | m_ack = true; 85 | break; 86 | case NN_REPORT: 87 | return HandleReport(packet); 88 | default: 89 | LOG_WARN("NatNeg", "Unknown packet type: %d", packet->packettype); 90 | return false; 91 | } 92 | 93 | return true; 94 | } 95 | 96 | bool CClient::HandleInitPacket(NatNegPacket* packet) 97 | { 98 | m_version = packet->version; 99 | 100 | if ((m_version > 1) && (packet->Packet.Init.porttype == 1)) 101 | { 102 | CClient* c = CClientManager::FindClientByCookieIndex(packet->cookie, m_clientindex); 103 | if (c != NULL && c != this) 104 | { 105 | m_punching.sin_port = c->GetPunchingAddr().sin_port; 106 | CClientManager::Delete(c); 107 | } 108 | } 109 | 110 | m_cookie = packet->cookie; 111 | m_clientindex = packet->Packet.Init.clientindex; 112 | packet->packettype = NN_INITACK; 113 | Write(packet, INITPACKET_SIZE); 114 | 115 | if (packet->Packet.Init.porttype > 1) 116 | return false; 117 | 118 | m_init = true; 119 | 120 | if ((m_version < 2) || (packet->Packet.Init.porttype == 1)) 121 | SendConnect(packet); 122 | 123 | return true; 124 | } 125 | 126 | void CClient::Write(void* data, int len) 127 | { 128 | CTemplateSocket::WriteUDP(m_stream, data, len, (const struct sockaddr*)&m_addr); 129 | } 130 | 131 | void CClient::SendConnect(NatNegPacket* packet, bool sendToOther) 132 | { 133 | if (m_ack || m_init == false) 134 | return; 135 | 136 | CClient* c = CClientManager::FindClientByCookieIndex(packet->cookie, m_clientindex); 137 | if (c != NULL && c != this) 138 | { 139 | NatNegPacket sendpacket = {0}; 140 | sendpacket.version = m_version; 141 | sendpacket.Packet.Connect.gotyourdata = 'B'; 142 | sendpacket.packettype = NN_CONNECT; 143 | sendpacket.cookie = m_cookie; 144 | memcpy(sendpacket.magic, NNMagicData, NATNEG_MAGIC_LEN); 145 | sendpacket.Packet.Connect.finished = FINISHED_NOERROR; 146 | if (!c->IsInit() || c->HaveAck()) 147 | return; 148 | 149 | c->AllowConnection(true); 150 | m_connected = true; 151 | 152 | sendpacket.Packet.Connect.remoteIP = c->GetPunchingAddr().sin_addr.s_addr; 153 | sendpacket.Packet.Connect.remotePort = c->GetPunchingAddr().sin_port; 154 | 155 | Write(&sendpacket, CONNECTPACKET_SIZE); 156 | 157 | m_connectTime = time(NULL); 158 | 159 | if(!sendToOther) 160 | return; 161 | 162 | c->SetConnectTime(time(NULL)); 163 | 164 | sendpacket.Packet.Connect.remoteIP = m_punching.sin_addr.s_addr; 165 | sendpacket.Packet.Connect.remotePort = m_punching.sin_port; 166 | 167 | Write(&sendpacket, CONNECTPACKET_SIZE); 168 | } 169 | } 170 | 171 | bool CClient::HandleAddressCheck(NatNegPacket* packet) 172 | { 173 | packet->packettype = NN_ADDRESS_REPLY; 174 | packet->Packet.Init.localip = m_addr.sin_addr.s_addr; 175 | packet->Packet.Init.localport = m_addr.sin_port; 176 | Write(packet, INITPACKET_SIZE); 177 | return true; 178 | } 179 | 180 | bool CClient::HandleNatifyRequest(NatNegPacket* packet) 181 | { 182 | int ret = 0; 183 | 184 | #ifdef _WIN32 185 | SOCKET ertsocket = INVALID_SOCKET; 186 | #else 187 | int ertsocket = 0; 188 | #endif 189 | 190 | struct sockaddr_in si, si_src; 191 | 192 | if (packet->Packet.Init.porttype == 1) 193 | Write(packet, INITPACKET_SIZE); 194 | 195 | ertsocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); 196 | if (ertsocket == -1) 197 | return false; 198 | 199 | si.sin_family = AF_INET; 200 | si.sin_port = m_addr.sin_port; 201 | si.sin_addr.s_addr = m_addr.sin_addr.s_addr; 202 | si_src.sin_family = AF_INET; 203 | 204 | si_src.sin_port = htons(MATCHUP_PORT); 205 | if (packet->Packet.Init.porttype == NN_PT_NN2 || packet->Packet.Init.porttype == NN_PT_NN3) 206 | { 207 | inet_pton(AF_INET, CNNServer::GetProbeIP(), &si_src.sin_addr.s_addr); 208 | } 209 | else 210 | inet_pton(AF_INET, CNNServer::GetMatchIP(), &si_src.sin_addr.s_addr); 211 | 212 | if (packet->Packet.Init.porttype == NN_PT_NN3) 213 | ret = connect(ertsocket, (struct sockaddr*)&si_src, sizeof(si_src)); 214 | else 215 | ret = bind(ertsocket, (struct sockaddr*)&si_src, sizeof(si_src)); 216 | 217 | if (ret != 0) 218 | return false; 219 | 220 | sendto(ertsocket, (char*)packet, INITPACKET_SIZE, 0, (struct sockaddr*)&si, sizeof(si)); 221 | close(ertsocket); 222 | 223 | return true; 224 | } 225 | 226 | bool CClient::HandleReport(NatNegPacket* packet) 227 | { 228 | packet->packettype = NN_REPORT_ACK; 229 | Write(packet, REPORTPACKET_SIZE); 230 | return true; 231 | } -------------------------------------------------------------------------------- /natneg/Client.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef NN_CLIENT_H 18 | #define NN_CLIENT_H 19 | 20 | #include 21 | #include 22 | 23 | #include "NNTypes.h" 24 | 25 | #ifdef _WIN32 26 | #include 27 | #else 28 | #include 29 | #endif 30 | 31 | class CClient 32 | { 33 | public: 34 | CClient(mdk_socket stream, const struct sockaddr_in* addr, CDatabase* db); 35 | ~CClient(); 36 | 37 | bool Handle(const char *buf, ssize_t len); 38 | 39 | inline unsigned short GetPort() { return m_port; } 40 | inline const char* GetIP() { return m_ip; } 41 | 42 | inline mdk_socket GetSocket() { return m_stream; } 43 | 44 | inline struct sockaddr_in* GetAddr() { return &m_addr; } 45 | 46 | void Disconnect(); 47 | 48 | // Operator overload 49 | bool operator==(CClient& c); 50 | bool operator!=(CClient& c); 51 | 52 | inline void SetConnectTime(time_t time) { m_connectTime = time; } 53 | inline void AllowConnection(bool c) { m_connected = c; } 54 | 55 | inline struct sockaddr_in GetPunchingAddr() { return m_punching; } 56 | 57 | inline bool IsInit() { return m_init; } 58 | inline bool HaveAck() { return m_ack; } 59 | 60 | inline int GetCookie() { return m_cookie; } 61 | inline unsigned char GetClientIndex() { return m_clientindex; } 62 | 63 | private: 64 | struct sockaddr_in m_addr; 65 | struct sockaddr_in m_punching; 66 | time_t m_lastpacket, m_connectTime; 67 | mdk_socket m_stream; 68 | bool m_ack; 69 | int m_cookie; 70 | unsigned char m_clientindex; 71 | unsigned char m_version; 72 | bool m_init; 73 | unsigned int m_instance; 74 | bool m_connected; 75 | unsigned short m_port; 76 | char m_ip[INET_ADDRSTRLEN]; 77 | 78 | protected: 79 | bool HandleInitPacket(NatNegPacket* packet); 80 | bool HandleReport(NatNegPacket* packet); 81 | bool HandleAddressCheck(NatNegPacket* packet); 82 | bool HandleNatifyRequest(NatNegPacket* packet); 83 | void SendConnect(NatNegPacket* packet, bool sendToOther = true); 84 | 85 | private: 86 | void Write(void* data, int len); 87 | 88 | CDatabase* m_dbConnect; 89 | }; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /natneg/ClientManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "ClientManager.h" 18 | 19 | #include 20 | 21 | void CClientManager::Free() 22 | { 23 | ClientMap::iterator it = m_clients.begin(); 24 | 25 | while (it != m_clients.end()) 26 | { 27 | // Free CClient memory 28 | if (it->second) 29 | delete it->second; 30 | 31 | it++; 32 | } 33 | 34 | m_clients.clear(); 35 | } 36 | 37 | void CClientManager::Delete(ClientMap::iterator it) 38 | { 39 | CTemplateServer* server = NULL; 40 | 41 | if (it == m_clients.end()) 42 | return; 43 | 44 | if (!it->second) 45 | return; 46 | 47 | delete (it->second); 48 | 49 | m_clients.erase(it); 50 | } 51 | 52 | bool CClientManager::CreateAndHandle(CDatabase* db, mdk_socket stream, const struct sockaddr_in* addr_in, const char *data, ssize_t len) 53 | { 54 | // Create che client 55 | CClient* c = new CClient(stream, addr_in, db); 56 | SClientStruct ss; 57 | 58 | inet_ntop(AF_INET, &(addr_in->sin_addr), ss.ip, INET_ADDRSTRLEN); 59 | 60 | ss.port = addr_in->sin_port; 61 | 62 | m_clients[ss] = c; 63 | 64 | if (!c->Handle(data, len)) 65 | { 66 | Delete(c); // Delete the client if it returned false 67 | return false; 68 | } 69 | 70 | return true; 71 | } 72 | 73 | bool CClientManager::Handle(CDatabase* con, mdk_socket stream, const struct sockaddr* addr, const char *data, ssize_t len) 74 | { 75 | ClientMap::iterator it; 76 | unsigned int i = 0; 77 | SClientStruct ss; 78 | struct sockaddr_in* addr_in = (struct sockaddr_in*)addr; 79 | 80 | inet_ntop(AF_INET, &(addr_in->sin_addr), ss.ip, INET_ADDRSTRLEN); 81 | ss.port = addr_in->sin_port; 82 | 83 | it = m_clients.find(ss); 84 | 85 | if (it == m_clients.end()) 86 | return CreateAndHandle(con, stream, addr_in, data, len); 87 | 88 | // Handle our client 89 | if (!it->second->Handle(data, len)) 90 | { 91 | Delete(it); // Delete the client if it returned false 92 | return false; 93 | } 94 | 95 | return true; 96 | } 97 | 98 | void CClientManager::Delete(CClient* c) 99 | { 100 | ClientMap::iterator it = m_clients.begin(); 101 | 102 | while (it != m_clients.end()) 103 | { 104 | CClient *cc = it->second; 105 | 106 | if (cc == c) 107 | { 108 | Delete(it); 109 | return; 110 | } 111 | 112 | it++; 113 | } 114 | } 115 | 116 | CClient* CClientManager::FindClientByCookieIndex(int cookie, unsigned char index) 117 | { 118 | ClientMap::iterator it = m_clients.begin(); 119 | 120 | while (it != m_clients.end()) 121 | { 122 | CClient *cc = it->second; 123 | 124 | if (cc->GetCookie() == cookie && cc->GetClientIndex() == index) 125 | return cc; 126 | 127 | it++; 128 | } 129 | 130 | return NULL; 131 | } 132 | 133 | 134 | ClientMap CClientManager::m_clients; 135 | -------------------------------------------------------------------------------- /natneg/ClientManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef NN_CLIENTMANAGER_H 18 | #define NN_CLIENTMANAGER_H 19 | 20 | #include "Client.h" 21 | 22 | #include 23 | 24 | #include 25 | 26 | struct SClientStruct 27 | { 28 | char ip[INET_ADDRSTRLEN]; 29 | unsigned short port; 30 | }; 31 | 32 | static inline bool operator< (const SClientStruct s1, const SClientStruct& s2) 33 | { 34 | return s1.port < s2.port; 35 | } 36 | 37 | typedef std::map ClientMap; 38 | 39 | class CClientManager 40 | { 41 | public: 42 | static bool Handle(CDatabase* db, mdk_socket stream, const struct sockaddr* addr, const char*data, ssize_t len); 43 | static void Free(); 44 | 45 | static CClient* FindClientByCookieIndex(int cookie, unsigned char index); 46 | 47 | static void Delete(CClient* c); 48 | 49 | private: 50 | static ClientMap m_clients; 51 | 52 | private: 53 | static void Delete(ClientMap::iterator ss); 54 | static bool CreateAndHandle(CDatabase* db, mdk_socket stream, const struct sockaddr_in* addr, const char *data, ssize_t len); 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /natneg/NNServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSEc See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "NNServer.h" 18 | #include "ClientManager.h" 19 | 20 | #include 21 | #include 22 | 23 | CNNServer::CNNServer(int defaultport, bool udp) : CThreadServer(defaultport, udp) {} 24 | 25 | CNNServer::~CNNServer() 26 | { 27 | CClientManager::Free(); 28 | } 29 | 30 | int CNNServer::Initialize() 31 | { 32 | if (!m_lpDatabase) 33 | return ERROR_DATABASE_ERROR; 34 | 35 | ModuleConfigMap::iterator it = m_cfg.find("MatchIP"); 36 | if (it == m_cfg.end()) 37 | { 38 | LOG_ERROR("NatNeg", "Cannot find option \"MatchIP\""); 39 | return ERROR_CONFIGURATION_ERROR; 40 | } 41 | SetMatchIP(it->second.c_str()); 42 | 43 | it = m_cfg.find("ProbeIP"); 44 | if (it == m_cfg.end()) 45 | { 46 | LOG_ERROR("NatNeg", "Cannot find option \"ProbeIP\""); 47 | return ERROR_CONFIGURATION_ERROR; 48 | } 49 | 50 | SetProbeIP(it->second.c_str()); 51 | 52 | 53 | return ERROR_NONE; 54 | } 55 | 56 | void CNNServer::OnUDPRead(mdk_socket client, const struct sockaddr* addr, const char *data, ssize_t size) 57 | { 58 | CClientManager::Handle(m_lpDatabase, client, addr, data, size); 59 | } 60 | 61 | char CNNServer::m_matchIp[INET_ADDRSTRLEN] = {0}; 62 | char CNNServer::m_probeIp[INET_ADDRSTRLEN] = {0}; 63 | 64 | ModuleEntryPoint(CNNServer, MATCHUP_PORT, true) 65 | -------------------------------------------------------------------------------- /natneg/NNServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef NNSERVER_H 18 | #define NNSERVER_H 19 | 20 | #include 21 | 22 | #include 23 | 24 | /* 25 | This class rappresents a Player Search server 26 | */ 27 | class CNNServer : public CThreadServer 28 | { 29 | public: 30 | CNNServer(int defaultport, bool udp); 31 | ~CNNServer(); 32 | 33 | int Initialize(); 34 | 35 | bool OnTCPNewConnection(mdk_socket stream, int status) { return true; } 36 | 37 | void OnTCPRead(mdk_socket client, const char *data, ssize_t size) {} 38 | void OnUDPRead(mdk_socket client, const struct sockaddr* addr, const char *data, ssize_t size); 39 | 40 | 41 | static const char* GetMatchIP() { return m_matchIp; } 42 | static const char* GetProbeIP() { return m_probeIp; } 43 | 44 | void SetMatchIP(const char* ip) { strncpy(m_matchIp, ip, INET_ADDRSTRLEN); } 45 | void SetProbeIP(const char* ip) { strncpy(m_probeIp, ip, INET_ADDRSTRLEN); } 46 | private: 47 | static char m_matchIp[INET_ADDRSTRLEN]; 48 | static char m_probeIp[INET_ADDRSTRLEN]; 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /natneg/NNTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef NNTYPES_H 18 | #define NNTYPES_H 19 | 20 | #define NN_PT_GP 0 21 | #define NN_PT_NN1 1 22 | #define NN_PT_NN2 2 23 | #define NN_PT_NN3 3 24 | 25 | #define MATCHUP_PORT 27901 26 | 27 | /* 28 | NAT Negotiation Packet Magic Bytes 29 | These bytes will start each incoming packet that is part of the NAT Negotiation SDK. 30 | If you are sharing a game socket with the SDK, you can use these bytes to determine when to 31 | pass a packet to NNProcessData 32 | */ 33 | #define NATNEG_MAGIC_LEN 6 34 | #define NN_MAGIC_0 0xFD 35 | #define NN_MAGIC_1 0xFC 36 | #define NN_MAGIC_2 0x1E 37 | #define NN_MAGIC_3 0x66 38 | #define NN_MAGIC_4 0x6A 39 | #define NN_MAGIC_5 0xB2 40 | 41 | #define NN_INIT 0 42 | #define NN_INITACK 1 43 | #define NN_ERTTEST 2 44 | #define NN_ERTACK 3 45 | #define NN_STATEUPDATE 4 46 | #define NN_CONNECT 5 47 | #define NN_CONNECT_ACK 6 48 | #define NN_CONNECT_PING 7 49 | #define NN_BACKUP_TEST 8 50 | #define NN_BACKUP_ACK 9 51 | #define NN_ADDRESS_CHECK 10 52 | #define NN_ADDRESS_REPLY 11 53 | #define NN_NATIFY_REQUEST 12 54 | #define NN_REPORT 13 55 | #define NN_REPORT_ACK 14 56 | 57 | #define FINISHED_NOERROR 0 58 | #define FINISHED_ERROR_DEADBEAT_PARTNER 1 59 | #define FINISHED_ERROR_INIT_PACKETS_TIMEDOUT 2 60 | 61 | typedef enum { no_nat, firewall_only, full_cone, restricted_cone, port_restricted_cone, symmetric, unknown, NUM_NAT_TYPES } NatType; 62 | typedef enum { unrecognized, private_as_public, consistent_port, incremental, mixed, NUM_MAPPING_SCHEMES } NatMappingScheme; 63 | 64 | #define INITPACKET_SIZE BASEPACKET_SIZE + 9 65 | #define INITPACKET_ADDRESS_OFFSET BASEPACKET_SIZE + 3 66 | typedef struct _InitPacket 67 | { 68 | unsigned char porttype; 69 | unsigned char clientindex; 70 | unsigned char usegameport; 71 | unsigned int localip; 72 | unsigned short localport; 73 | } InitPacket; 74 | 75 | #define REPORTPACKET_SIZE BASEPACKET_SIZE + 61 76 | typedef struct _ReportPacket 77 | { 78 | unsigned char porttype; 79 | unsigned char clientindex; 80 | unsigned char negResult; 81 | NatType natType; 82 | NatMappingScheme natMappingScheme; 83 | char gamename[50]; 84 | } ReportPacket; 85 | 86 | #define CONNECTPACKET_SIZE BASEPACKET_SIZE + 8 87 | typedef struct _ConnectPacket 88 | { 89 | unsigned int remoteIP; 90 | unsigned short remotePort; 91 | unsigned char gotyourdata; 92 | unsigned char finished; 93 | } ConnectPacket; 94 | 95 | #define BASEPACKET_SIZE 12 96 | #define BASEPACKET_TYPE_OFFSET 7 97 | typedef struct _NatNegPacket { 98 | // Base members: 99 | unsigned char magic[NATNEG_MAGIC_LEN]; 100 | unsigned char version; 101 | unsigned char packettype; 102 | int cookie; 103 | 104 | union 105 | { 106 | InitPacket Init; 107 | ConnectPacket Connect; 108 | ReportPacket Report; 109 | } Packet; 110 | 111 | } NatNegPacket; 112 | 113 | #endif -------------------------------------------------------------------------------- /peerchat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | ${CMAKE_CURRENT_LIST_DIR}/PeerChatServer.h 3 | ${CMAKE_CURRENT_LIST_DIR}/PeerChatServer.cpp 4 | ${CMAKE_CURRENT_LIST_DIR}/Cache.h 5 | ${CMAKE_CURRENT_LIST_DIR}/Cache.cpp 6 | ${CMAKE_CURRENT_LIST_DIR}/IRCClient.h 7 | ${CMAKE_CURRENT_LIST_DIR}/IRCChannel.cpp 8 | ${CMAKE_CURRENT_LIST_DIR}/IRCClient.h 9 | ${CMAKE_CURRENT_LIST_DIR}/IRCClient.cpp 10 | ${CMAKE_CURRENT_LIST_DIR}/Structs.h 11 | ) 12 | 13 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../common") 14 | 15 | add_library(PeerChat SHARED ${SOURCES}) 16 | target_link_libraries(PeerChat RetroSpyCommon) 17 | -------------------------------------------------------------------------------- /peerchat/Cache.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "Cache.h" 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #ifdef _WIN32 27 | #define strcasecmp _stricmp 28 | #endif 29 | 30 | CCache::CCache() 31 | { 32 | m_instance = this; 33 | m_sReservedClientID = 0; 34 | } 35 | 36 | CCache::~CCache() 37 | { 38 | TClientMap::iterator it = m_clients.begin(); 39 | for (; it != m_clients.end(); it++) 40 | { 41 | delete (*it).second; 42 | } 43 | 44 | TChannelVector::iterator it2 = m_channels.begin(); 45 | for (; it2 != m_channels.end(); it2++) 46 | { 47 | delete (*it2); 48 | } 49 | 50 | m_channels.clear(); 51 | m_clients.clear(); 52 | 53 | m_vUserProps.clear(); 54 | m_vGameClients.clear(); 55 | m_vChannelProps.clear(); 56 | 57 | m_instance = NULL; 58 | } 59 | 60 | bool CCache::AddUser(mdk_socket socket) 61 | { 62 | if (m_sReservedClientID == SIZE_MAX) 63 | return false; // Reached max clients supported 64 | 65 | CIRCClient* cc = new CIRCClient(socket, m_sReservedClientID); 66 | if (!cc) 67 | return false; 68 | 69 | m_sReservedClientID++; 70 | return true; 71 | } 72 | 73 | CIRCClient* CCache::GetUser(unsigned long long id) 74 | { 75 | return NULL; 76 | } 77 | 78 | void CCache::DelUser(unsigned long long id) 79 | { 80 | //already done in ~Cache(); 81 | } 82 | 83 | bool CCache::LoadData(CDatabase* db) 84 | { 85 | CResultSet* res = new CResultSet(); 86 | 87 | if (res->ExecuteQuery(db, "SELECT `key`,`mask`,`comment`,`entrymsg`,UNIX_TIMESTAMP(`expires`), `groupname`, `limit`, `mode`, `onlyowner`, `setbynick`, `setbypid`, UNIX_TIMESTAMP(`setondate`), `topic`, `setbyhost` FROM `channel_properties")) 88 | { 89 | if (res->GotoFirstRow()) 90 | { 91 | do 92 | { 93 | SChannelProps props; 94 | memset(&props, 0, sizeof(props)); 95 | strncpy(props.key, res->GetStringFromRow(0).c_str(), MAX_NAME+1); 96 | strncpy(props.mask, res->GetStringFromRow(1).c_str(), MAX_NAME+1); 97 | strncpy(props.comment, res->GetStringFromRow(2).c_str(), MAX_COMMENT + 1); 98 | strncpy(props.entrymsg, res->GetStringFromRow(3).c_str(), MAX_COMMENT + 1); 99 | props.expires = res->GetIntFromRow(4); 100 | strncpy(props.groupname, res->GetStringFromRow(5).c_str(), MAX_NAME + 1); 101 | props.limit = res->GetIntFromRow(6); 102 | strncpy(props.modes, res->GetStringFromRow(7).c_str(), MAX_NAME + 1); 103 | props.onlyowner = res->GetIntFromRow(8); 104 | 105 | if (res->GetStringFromRow(9).c_str()[0] != 0) 106 | strncpy(props.setbynick, res->GetStringFromRow(9).c_str(), MAX_NAME + 1); 107 | else 108 | strncpy(props.setbynick, "SERVER", MAX_NAME + 1); 109 | 110 | props.setbypid = res->GetUIntFromRow(10); 111 | props.setondate = res->GetIntFromRow(11); 112 | strncpy(props.topic, res->GetStringFromRow(12).c_str(), MAX_COMMENT + 1); 113 | strncpy(props.setbyhost, res->GetStringFromRow(13).c_str(), MAX_NAME + 1); 114 | 115 | m_vChannelProps.push_back(props); 116 | UpdateChannelProperties(props, false); 117 | } while (res->GotoNextRow()); 118 | } 119 | } 120 | 121 | if (res->ExecuteQuery(db, "SELECT `mask`,`comment`,UNIX_TIMESTAMP(`expires`),`hostmask`,`machineid`,`modeflags`,`profileid`,`setbyhost`,`setbynick`,`setbypid`,UNIX_TIMESTAMP(`setondate`),`usermodeid` FROM `channel_user_properties`")) 122 | { 123 | if (res->GotoFirstRow()) 124 | { 125 | do 126 | { 127 | SUserProps usermode; 128 | memset(&usermode,0,sizeof(usermode)); 129 | strncpy(usermode.mask, res->GetStringFromRow(0).c_str(), MAX_NAME+1); 130 | strncpy(usermode.comment, res->GetStringFromRow(1).c_str(), MAX_COMMENT+1); 131 | usermode.expires = res->GetIntFromRow(2); 132 | strncpy(usermode.hostmask, res->GetStringFromRow(3).c_str(), MAX_NAME+1); 133 | strncpy(usermode.machineid, res->GetStringFromRow(4).c_str(), MAX_NAME+1); 134 | usermode.modeflags = res->GetIntFromRow(5); 135 | usermode.profileid = res->GetIntFromRow(6); 136 | strncpy(usermode.setbyhost, res->GetStringFromRow(7).c_str(), MAX_NAME+1); 137 | strncpy(usermode.setbynick, res->GetStringFromRow(8).c_str(), MAX_NAME+1); 138 | usermode.setbypid = res->GetIntFromRow(9); 139 | usermode.setondate = res->GetIntFromRow(10); 140 | usermode.usermodeid = res->GetIntFromRow(11); 141 | usermode.isGlobal = 1; 142 | 143 | m_vUserProps.push_back(usermode); 144 | UpdateUserModes(usermode); 145 | } while (res->GotoNextRow()); 146 | } 147 | } 148 | 149 | if (res->ExecuteQuery(db, "SELECT `mask`,`gameid` FROM `channel_clients`")) 150 | { 151 | if (res->GotoFirstRow()) 152 | { 153 | do 154 | { 155 | SGameClient client; 156 | memset(&client,0,sizeof(client)); 157 | 158 | strncpy(client.mask, res->GetStringFromRow(0).c_str(), res->GetStringFromRow(0).length() % sizeof(client.mask)); 159 | client.gameid = res->GetIntFromRow(1); 160 | 161 | m_vGameClients.push_back(client); 162 | } while (res->GotoNextRow()); 163 | } 164 | } 165 | 166 | if (res->ExecuteQuery(db, "SELECT `profileid`, `rightsmask` FROM `operators`")) 167 | { 168 | if (res->GotoFirstRow()) 169 | { 170 | do 171 | { 172 | AddOperator(res->GetUIntFromRow(0), res->GetUIntFromRow(1)); 173 | } while (res->GotoNextRow()); 174 | } 175 | } 176 | 177 | delete res; 178 | return true; 179 | } 180 | 181 | void CCache::UpdateChannelProperties(SChannelProps props, bool kickexisting) 182 | { 183 | TChannelVector::iterator it = m_channels.begin(); 184 | CIRCChannel* chan = NULL; 185 | 186 | if (strchr(props.modes, 'z') != NULL && strchr(props.mask, '*') == NULL) 187 | { 188 | if (FindChannel(props.mask) == NULL) 189 | { 190 | chan = new CIRCChannel(props.mask); 191 | chan->UpdateChannelProperties(props, false); 192 | return; 193 | } 194 | } 195 | 196 | while (it != m_channels.end()) 197 | { 198 | chan = *it; 199 | 200 | if (match_mask_with_name(props.mask, (const char*)chan->GetName()) == 0) 201 | { 202 | if (GetClosestChannelProperties(chan->GetName()) == props) 203 | chan->UpdateChannelProperties(props, kickexisting); 204 | } 205 | 206 | it++; 207 | } 208 | } 209 | 210 | CIRCChannel* CCache::FindChannel(const char* name) 211 | { 212 | TChannelVector::iterator it = m_channels.begin(); 213 | 214 | while (it != m_channels.end()) 215 | { 216 | if (strcasecmp(name, (*it)->GetName()) == 0) 217 | return *it; 218 | 219 | it++; 220 | } 221 | 222 | return NULL; 223 | } 224 | 225 | CCache* CCache::m_instance = NULL; 226 | -------------------------------------------------------------------------------- /peerchat/Cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef _CACHE_H_ 18 | #define _CACHE_H_ 19 | 20 | #include "IRCClient.h" 21 | #include "IRCChannel.h" 22 | #include "Structs.h" 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | typedef std::map TClientMap; 30 | typedef std::vector TChannelVector; 31 | 32 | class CCache 33 | { 34 | public: 35 | CCache(); 36 | ~CCache(); 37 | 38 | bool LoadData(CDatabase * db); 39 | 40 | bool AddUser(mdk_socket socket); 41 | CIRCClient* GetUser(unsigned long long id); 42 | void DelUser(unsigned long long id); 43 | 44 | inline static CCache* Instance() { return m_instance; } 45 | 46 | CIRCChannel* FindChannel(const char* name); 47 | 48 | void UpdateChannelProperties(SChannelProps props, bool kickexisting); 49 | void UpdateUserModes(SUserProps props); 50 | 51 | protected: 52 | TClientMap m_clients; 53 | TChannelVector m_channels; 54 | 55 | std::vector m_vUserProps; 56 | std::vector m_vChannelProps; 57 | std::vector m_vGameClients; 58 | 59 | unsigned long long m_sReservedClientID; 60 | 61 | void AddOperator(unsigned int id, unsigned int mask); 62 | SChannelProps GetClosestChannelProperties(const char* name); 63 | 64 | private: 65 | static CCache* m_instance; 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /peerchat/IRCChannel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "IRCChannel.h" 18 | -------------------------------------------------------------------------------- /peerchat/IRCChannel.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef _IRCCHANNEL_H_ 18 | #define _IRCCHANNEL_H_ 19 | 20 | #include "Structs.h" 21 | 22 | class CIRCChannel 23 | { 24 | public: 25 | CIRCChannel(const char* mask); 26 | ~CIRCChannel(); 27 | 28 | const char * GetName(); 29 | 30 | void UpdateChannelProperties(SChannelProps props, bool kickexisting); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /peerchat/IRCClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "IRCClient.h" 18 | 19 | -------------------------------------------------------------------------------- /peerchat/IRCClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef _IRCCLIENT_H_ 18 | #define _IRCCLIENT_H_ 19 | 20 | #include 21 | 22 | class CIRCClient 23 | { 24 | public: 25 | CIRCClient(mdk_socket sock, unsigned long long id); 26 | ~CIRCClient(); 27 | 28 | void Process(const char* data, ssize_t size); 29 | void Close(); 30 | 31 | inline unsigned long long GetID () { return m_ullID; } 32 | 33 | protected: 34 | unsigned long long m_ullID; 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /peerchat/PeerChatServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "PeerChatServer.h" 18 | 19 | #include "Cache.h" 20 | 21 | #include 22 | #include 23 | 24 | PeerChatServer::PeerChatServer(int defaultport, bool udp) : CThreadServer(defaultport, udp) 25 | { 26 | m_cache = new CCache(); 27 | } 28 | 29 | PeerChatServer::~PeerChatServer() 30 | { 31 | if (m_cache) 32 | delete m_cache; 33 | 34 | m_cache = NULL; 35 | } 36 | 37 | bool PeerChatServer::OnTCPNewConnection(mdk_socket stream, int status) 38 | { 39 | if (m_cache->AddUser(stream)) 40 | return false; 41 | 42 | return true; 43 | } 44 | 45 | void PeerChatServer::OnTCPRead(mdk_socket client, const char *data, ssize_t size) 46 | { 47 | if (GetSocketExtraData(client)->GetData() == NULL) 48 | { 49 | // No client pointer! 50 | Close(client); 51 | return; 52 | } 53 | 54 | ((CIRCClient*)GetSocketExtraData(client)->GetData())->Process(data, size); 55 | } 56 | 57 | int PeerChatServer::Initialize() 58 | { 59 | if (!m_lpDatabase) 60 | return ERROR_DATABASE_ERROR; 61 | 62 | return ERROR_NONE; 63 | } 64 | 65 | ModuleEntryPoint(PeerChatServer, 6667, false) 66 | -------------------------------------------------------------------------------- /peerchat/PeerChatServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef PEERCHATSERVER_H 18 | #define PEERCHATSERVER_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "Cache.h" 25 | 26 | /* 27 | This class rappresents a Peer Chat Server 28 | */ 29 | class PeerChatServer : public CThreadServer 30 | { 31 | public: 32 | PeerChatServer(int defaultport, bool udp); 33 | ~PeerChatServer(); 34 | 35 | int Initialize(); 36 | 37 | /* See CServer::OnNewConnection */ 38 | bool OnTCPNewConnection(mdk_socket stream, int status); 39 | 40 | void OnTCPRead(mdk_socket client, const char *data, ssize_t size); 41 | void OnUDPRead(mdk_socket client, const struct sockaddr*, const char *, ssize_t) {} //Waste UDP 42 | 43 | protected: 44 | CCache* m_cache; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /peerchat/Structs.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef _STRUCTS_H_ 18 | #define _STRUCTS_H_ 19 | 20 | #include 21 | #include 22 | 23 | #define MAX_NAME 64 24 | #define MAX_COMMENT 256 25 | 26 | typedef struct { 27 | char mask[MAX_NAME + 1]; 28 | char comment[MAX_COMMENT + 1]; 29 | time_t expires; 30 | char hostmask[MAX_NAME + 1]; 31 | char machineid[MAX_NAME + 1]; 32 | int modeflags; 33 | int profileid; 34 | char setbyhost[MAX_NAME + 1]; 35 | char setbynick[MAX_NAME + 1]; 36 | int setbypid; 37 | int usermodeid; 38 | char isGlobal; //is it temp or stored in db 39 | char hideNick; //only used while setting it(remove when we use the db msgs to do this) 40 | time_t setondate; 41 | } SUserProps; 42 | 43 | typedef struct { 44 | char key[MAX_NAME + 1]; 45 | char mask[MAX_NAME + 1]; 46 | char comment[MAX_COMMENT + 1]; 47 | char entrymsg[MAX_COMMENT + 1]; 48 | time_t expires; 49 | char groupname[MAX_NAME + 1]; 50 | int limit; 51 | char modes[MAX_NAME + 1]; 52 | char onlyowner; 53 | char setbynick[MAX_NAME + 1]; 54 | char setbyhost[MAX_NAME + 1]; 55 | int setbypid; 56 | char topic[MAX_COMMENT + 1]; 57 | time_t setondate; 58 | } SChannelProps; 59 | 60 | typedef struct { 61 | char mask[MAX_NAME + 1]; 62 | int gameid;//-1 = all encrypted, 0 = unencrypted or anything, otherwise specific gameid 63 | } SGameClient; 64 | 65 | static bool operator==(const SChannelProps& p1, const SChannelProps& p2) 66 | { 67 | if (strcmp(p1.key, p2.key) != 0) return false; 68 | if (strcmp(p1.mask, p2.mask) != 0) return false; 69 | if (strcmp(p1.comment, p2.comment) != 0) return false; 70 | if (strcmp(p1.entrymsg, p2.entrymsg) != 0) return false; 71 | if (p1.expires != p2.expires) return false; 72 | if (strcmp(p1.groupname, p2.groupname) != 0) return false; 73 | if (p1.limit != p2.limit) return false; 74 | if (strcmp(p1.modes, p2.modes) != 0) return false; 75 | if (p1.onlyowner != p2.onlyowner) return false; 76 | if (strcmp(p1.setbynick, p2.setbynick) != 0) return false; 77 | if (strcmp(p1.setbyhost, p2.setbyhost) != 0) return false; 78 | if (p1.setbypid != p2.setbypid) return false; 79 | if (strcmp(p1.topic, p2.topic) != 0) return false; 80 | if (p1.setondate != p2.setondate) return false; 81 | 82 | return true; 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /playersearch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | ${CMAKE_CURRENT_LIST_DIR}/PSServer.cpp 3 | ${CMAKE_CURRENT_LIST_DIR}/PSServer.h 4 | ) 5 | 6 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../common") 7 | 8 | add_library(PlayerSearch SHARED ${SOURCES}) 9 | target_link_libraries(PlayerSearch RetroSpyCommon) 10 | -------------------------------------------------------------------------------- /playersearch/PSServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSEc See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "PSServer.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #ifdef _WIN32 29 | #define strcasecmp _stricmp 30 | #endif 31 | 32 | PSServer::PSServer(int defaultport, bool udp) : CTemplateStringServer(defaultport, udp) {} 33 | PSServer::~PSServer() {} 34 | 35 | int PSServer::Initialize() 36 | { 37 | if (!m_lpDatabase) 38 | return ERROR_DATABASE_ERROR; 39 | 40 | return ERROR_NONE; 41 | } 42 | 43 | bool PSServer::HandleRequest(mdk_socket stream, const char *req, const char *buf, int size) 44 | { 45 | if (strcasecmp(req, "valid") == 0) 46 | return OnValid(stream, buf, size); 47 | else if (strcasecmp(req, "nicks") == 0) 48 | return OnSendNicks(stream, buf, size); 49 | else if (strcasecmp(req, "check") == 0) 50 | return OnCheckNicks(stream, buf, size); 51 | else if (strcasecmp(req, "search") == 0) 52 | return OnSearchUsers(stream, buf, size); 53 | else if (strcasecmp(req, "others") == 0) 54 | return OnReverseBuddies(stream, buf, size); 55 | else if (strcasecmp(req, "otherslist") == 0) 56 | return OnOthersList(stream, buf, size); 57 | else if (strcasecmp(req, "uniquesearch") == 0) 58 | return OnUniqueSearch(stream, buf, size); 59 | else if (strcasecmp(req, "profilelist") == 0) 60 | return OnProfileList(stream, buf, size); 61 | else if (strcasecmp(req, "pmatch") == 0) 62 | return OnProductMatching(stream, buf, size); 63 | else if (strcasecmp(req, "newuser") == 0) 64 | return OnNewUser(stream, buf, size); 65 | 66 | LOG_ERROR("PlayerSearch", "Unknown request \"%s\" received!", req); 67 | return false; 68 | } 69 | 70 | // Unused 71 | bool PSServer::OnTCPNewConnection(mdk_socket, int) { return true; } 72 | 73 | bool PSServer::OnValid(mdk_socket client, const char *buf, int) 74 | { 75 | std::string buffer=""; 76 | std::string email = ""; 77 | CResultSet *result = NULL; 78 | 79 | if (!get_gs_data(buf, email, "email")) 80 | { 81 | return false; 82 | } 83 | 84 | result = new CResultSet(); 85 | 86 | buffer = "SELECT COUNT(userid) FROM `users` WHERE `email` = '"; 87 | if (!mdk_escape_query_string(m_lpDatabase, email)) 88 | { 89 | delete result; 90 | return false; 91 | } 92 | buffer += email; 93 | buffer += "'"; 94 | 95 | if (!result->ExecuteQuery(m_lpDatabase, buffer)) 96 | { 97 | delete result; 98 | return false; 99 | } 100 | 101 | if (!result->GotoFirstRow()) 102 | WriteTCP(client, "\\vr\\0\\final\\"); 103 | 104 | if (result->GetIntFromRow(0) < 1) 105 | WriteTCP(client, "\\vr\\0\\final\\"); 106 | else 107 | WriteTCP(client, "\\vr\\1\\final\\"); 108 | 109 | delete result; 110 | return true; 111 | } 112 | 113 | bool PSServer::OnSendNicks(mdk_socket stream, const char *buf, int) 114 | { 115 | std::string email = "", pass = "", gamename = "", str = ""; 116 | bool bSendUnique = false; 117 | size_t i = 0; 118 | CResultSet *result = NULL; 119 | 120 | // Get data from buffer 121 | 122 | if (!get_gs_data(buf, email, "email")) 123 | return false; 124 | 125 | if (get_gs_data(buf, pass, "passenc")) 126 | { 127 | // Uncrypt the password 128 | gs_pass_decode(pass); 129 | } 130 | else 131 | { 132 | if (!get_gs_data(buf, pass, "pass")) 133 | return false; 134 | } 135 | 136 | if (get_gs_data(buf, gamename, "gamename")) 137 | bSendUnique = true; 138 | 139 | // Create the query and execute it 140 | str = "SELECT profiles.nick, profiles.uniquenick FROM profiles INNER " 141 | "JOIN users ON profiles.userid=users.userid WHERE users.email='"; 142 | if (!mdk_escape_query_string(m_lpDatabase, email)) 143 | return false; 144 | 145 | str += email; 146 | str += "' AND password='"; 147 | if (!mdk_escape_query_string(m_lpDatabase, pass)) 148 | return false; 149 | 150 | str += pass; 151 | str += "'"; 152 | 153 | result = new CResultSet(); 154 | 155 | if (!result->ExecuteQuery(m_lpDatabase, str)) 156 | { 157 | delete result; 158 | 159 | WriteTCP(stream, "\\nr\\\\ndone\\final\\"); 160 | return false; 161 | } 162 | 163 | if (!result->GotoFirstRow()) 164 | { 165 | delete result; 166 | 167 | WriteTCP(stream, "\\nr\\\\ndone\\final\\"); 168 | return false; 169 | 170 | } 171 | 172 | str = "\\nr\\" + std::to_string(result->GetTotalRows()); 173 | 174 | // Get all the nicks and store them 175 | do 176 | { 177 | str += "\\nick\\"; 178 | str += result->GetStringFromRow(0); 179 | 180 | if (bSendUnique) 181 | { 182 | str += "\\uniquenick\\"; 183 | str += result->GetStringFromRow(1); 184 | } 185 | } while(result->GotoNextRow()); 186 | 187 | str += "\\ndone\\final\\"; 188 | 189 | // Send to the socket 190 | WriteTCP(stream, str); 191 | 192 | delete result; 193 | 194 | return true; 195 | } 196 | 197 | bool PSServer::OnCheckNicks(mdk_socket stream, const char *buf, int) 198 | { 199 | char email[GP_EMAIL_LEN], nick[GP_NICK_LEN], pass[GP_PASSWORD_LEN], passenc[GP_PASSWORDENC_LEN]; 200 | unsigned int id = 0; 201 | 202 | if (!get_gs_data(buf, "email", email, GP_EMAIL_LEN)) 203 | return false; 204 | 205 | if (!get_gs_data(buf, "passenc", passenc, GP_PASSWORDENC_LEN)) 206 | { 207 | if (!get_gs_data(buf, "pass", passenc, GP_PASSWORD_LEN)) 208 | { 209 | LOG_ERROR("PlayerSearch", "No passenc passed on OnCheckNicks: %s!", buf); 210 | LOG_INFO("PlayerSearch", "Please report this message (including the body) to any contributor!"); 211 | return false; 212 | } 213 | } 214 | // else 215 | // { 216 | gs_pass_decode(passenc, pass); 217 | // } 218 | 219 | if (!get_gs_data(buf, "nick", nick, GP_NICK_LEN)) 220 | { 221 | LOG_ERROR("PlayerSearch", "No nicks passed on OnCheckNicks: %s!", buf); 222 | LOG_INFO("PlayerSearch", "Please report this message (including the body) to any contributor!"); 223 | return false; 224 | } 225 | 226 | if (!GetProfileIDFromNickEmailAndPass(m_lpDatabase, nick, email, pass, &id)) 227 | { 228 | snprintf(email, GP_EMAIL_LEN, "\\err\\%d\\final\\", GP_CHECK_BAD_PASSWORD); 229 | WriteTCP(stream, email); 230 | return false; 231 | } 232 | 233 | // TODO: Shouldn't be there some nicknames after cur? 234 | snprintf(email, GP_EMAIL_LEN, "\\cur\\0\\pid\\%d\\final\\", id); 235 | WriteTCP(stream, email); 236 | return false; 237 | } 238 | 239 | bool PSServer::OnSearchUsers(mdk_socket, const char *buf, int) 240 | { 241 | LOG_ERROR("PlayerSearch", "Received body for SearchUsers: %s!", buf); 242 | LOG_INFO("PlayerSearch", "Please report this message (including the body) to any contributor!"); 243 | 244 | return false; 245 | } 246 | 247 | /* 248 | This function sends all the friends of an user 249 | */ 250 | bool PSServer::OnReverseBuddies(mdk_socket socket, const char *buf, int) 251 | { 252 | /* 253 | GP_MASK_EMAIL = 0x00000020, 254 | */ 255 | CResultSet* rs = NULL; 256 | std::string query = ""; 257 | unsigned int profileid = 0; 258 | 259 | if (!get_gs_data(buf, query, "profileid")) 260 | return false; 261 | 262 | profileid = (unsigned int)std::stol(query); 263 | 264 | query = "SELECT profiles.profileid, nick, uniquenick, firstname, lastname, users.email, publicmask FROM profiles INNER JOIN friends ON profiles.profileid = friends.profileid INNER JOIN users ON users.userid = profiles.userid WHERE friends.targetid = "; 265 | query += std::to_string(profileid); 266 | 267 | rs = new CResultSet(); 268 | 269 | if (!rs->ExecuteQuery(m_lpDatabase, query)) 270 | { 271 | delete rs; 272 | return false; 273 | } 274 | 275 | if (!rs->GotoFirstRow()) 276 | { 277 | WriteTCP(socket, "\\others\\\\odone\\final\\"); 278 | delete rs; 279 | return true; 280 | } 281 | 282 | query = "\\others\\"; 283 | 284 | do 285 | { 286 | query += "o\\"; 287 | query += rs->GetUIntFromRow(0); 288 | query += "\\nick\\"; 289 | query += rs->GetStringFromRow(1); 290 | query += "\\uniquenick\\"; 291 | query += rs->GetStringFromRow(2); 292 | query += "\\first\\"; 293 | query += rs->GetStringFromRow(3); 294 | query += "\\last\\"; 295 | query += rs->GetStringFromRow(4); 296 | query += "\\email\\"; 297 | 298 | if (rs->GetIntFromRow(6) & GP_MASK_EMAIL) 299 | { 300 | query += rs->GetStringFromRow(5); 301 | } 302 | 303 | query += "\\"; 304 | } while (rs->GotoNextRow()); 305 | 306 | query += "\\odone\\final\\"; 307 | 308 | WriteTCP(socket, query); 309 | 310 | delete rs; 311 | return true; 312 | } 313 | 314 | bool PSServer::OnOthersList(mdk_socket, const char *buf, int) 315 | { 316 | LOG_ERROR("PlayerSearch", "Received body for OnOthersList: %s!", buf); 317 | LOG_INFO("PlayerSearch", "Please report this message (including the body) to any contributor!"); 318 | 319 | return false; 320 | } 321 | 322 | bool PSServer::OnUniqueSearch(mdk_socket stream, const char *buf, int) 323 | { 324 | char preferrednick[GP_NICK_LEN]; 325 | std::string sendmsg = "\\us\\7"; 326 | 327 | preferrednick[0] = 0; 328 | 329 | if (!get_gs_data(buf, "preferrednick", preferrednick, sizeof(preferrednick))) 330 | return false; 331 | 332 | // TODO: Change this to something more real 333 | 334 | gs_make_valid(preferrednick); 335 | 336 | // 7 times (us=7) 337 | sendmsg += "\\nick\\"; 338 | sendmsg += preferrednick; 339 | sendmsg += "\\nick\\"; 340 | sendmsg += preferrednick; 341 | sendmsg += "\\nick\\"; 342 | sendmsg += preferrednick; 343 | sendmsg += "\\nick\\"; 344 | sendmsg += preferrednick; 345 | sendmsg += "\\nick\\"; 346 | sendmsg += preferrednick; 347 | sendmsg += "\\nick\\"; 348 | sendmsg += preferrednick; 349 | sendmsg += "\\nick\\"; 350 | sendmsg += preferrednick; 351 | 352 | sendmsg += "\\usdone\\final\\"; 353 | 354 | WriteTCP(stream, sendmsg); 355 | 356 | return true; 357 | } 358 | 359 | bool PSServer::OnProfileList(mdk_socket, const char *buf, int) 360 | { 361 | LOG_ERROR("PlayerSearch", "Received body for OnProfileList: %s!", buf); 362 | LOG_INFO("PlayerSearch", "Please report this message (including the body) to any contributor!"); 363 | 364 | return false; 365 | } 366 | 367 | bool PSServer::OnProductMatching(mdk_socket, const char *buf, int) 368 | { 369 | LOG_ERROR("PlayerSearch", "Received body for OnProductMatching: %s!", buf); 370 | LOG_INFO("PlayerSearch", "Please report this message (including the body) to any contributor!"); 371 | 372 | return false; 373 | } 374 | 375 | bool PSServer::OnNewUser(mdk_socket stream, const char *buf, int size) 376 | { 377 | char email[GP_EMAIL_LEN], pass[GP_PASSWORD_LEN], nick[GP_NICK_LEN]; 378 | unsigned int userid = 0; 379 | 380 | if (!get_gs_data(buf, "email", email, sizeof(email))) 381 | { 382 | // Added this because OpenSpy reports an Unique Nickname usage 383 | LOG_ERROR("PlayerSearch", "Received mysterious body for OnNewUser: %s!", buf); 384 | LOG_INFO("PlayerSearch", "Please report the error message to any contributor if you see something similar to \"uniquenick\" or \"authtoken\"!"); 385 | 386 | return false; 387 | } 388 | 389 | if (!get_gs_data(buf, "pass", pass, sizeof(pass))) 390 | return false; 391 | 392 | if (!get_gs_data(buf, "nick", nick, sizeof(nick))) 393 | { 394 | // Added this because OpenSpy reports an Unique Nickname usage 395 | 396 | LOG_ERROR("PlayerSearch", "Received mysterious body for OnNewUser: %s!", buf); 397 | LOG_INFO("PlayerSearch", "Please report the error message to any contributor if you see something similar to \"uniquenick\" or \"authtoken\"!"); 398 | 399 | return false; 400 | } 401 | 402 | if (!GetUserIDFromEmail(m_lpDatabase, email, &userid)) 403 | { 404 | // user does not exist 405 | int ec = RegisterUser(m_lpDatabase, email, nick, pass, &userid); 406 | 407 | if (ec != -1) 408 | { 409 | snprintf(email, GP_EMAIL_LEN, "\\nur\\%d\\final\\", ec); 410 | WriteTCP(stream, email); 411 | return false; 412 | } 413 | } 414 | 415 | if (!GetProfileIDFromNickEmailAndPass(m_lpDatabase, nick, email, pass, &userid)) 416 | { 417 | snprintf(email, GP_EMAIL_LEN, "\\nur\\%u\\final\\", GP_NEWUSER_BAD_PASSWORD); 418 | WriteTCP(stream, email); 419 | return false; 420 | } 421 | 422 | snprintf(email, GP_EMAIL_LEN, "\\nur\\0\\pid\\%u\\final\\", userid); 423 | 424 | WriteTCP(stream, email); 425 | 426 | return true; 427 | } 428 | 429 | ModuleEntryPoint(PSServer, 29901, false) 430 | 431 | -------------------------------------------------------------------------------- /playersearch/PSServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef GPSPSERVER_H 18 | #define GPSPSERVER_H 19 | 20 | #include 21 | #include 22 | 23 | /* 24 | This class rappresents a Player Search server 25 | */ 26 | class PSServer : public CTemplateStringServer 27 | { 28 | public: 29 | PSServer(int defaultport, bool udp); 30 | ~PSServer(); 31 | 32 | int Initialize(); 33 | 34 | /* See CServer::OnNewConnection */ 35 | bool OnTCPNewConnection(mdk_socket stream, int status); 36 | 37 | /* See CStringServer::HandleRequest */ 38 | bool HandleRequest(mdk_socket stream, const char *req, const char *buf, int size); 39 | 40 | private: 41 | bool OnValid(mdk_socket stream, const char *buf, int size); 42 | bool OnSendNicks(mdk_socket stream, const char *buf, int size); 43 | bool OnCheckNicks(mdk_socket stream, const char *buf, int size); 44 | bool OnSearchUsers(mdk_socket stream, const char *buf, int size); 45 | bool OnReverseBuddies(mdk_socket stream, const char *buf, int size); 46 | bool OnOthersList(mdk_socket stream, const char *buf, int size); 47 | bool OnUniqueSearch(mdk_socket stream, const char *buf, int size); 48 | bool OnProfileList(mdk_socket stream, const char *buf, int size); 49 | bool OnProductMatching(mdk_socket stream, const char *buf, int size); 50 | bool OnNewUser(mdk_socket stream, const char *buf, int size); 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /playerspy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | ${CMAKE_CURRENT_LIST_DIR}/Client.cpp 3 | ${CMAKE_CURRENT_LIST_DIR}/Client.h 4 | ${CMAKE_CURRENT_LIST_DIR}/ClientManager.cpp 5 | ${CMAKE_CURRENT_LIST_DIR}/ClientManager.h 6 | ${CMAKE_CURRENT_LIST_DIR}/PYServer.cpp 7 | ${CMAKE_CURRENT_LIST_DIR}/PYServer.h 8 | ${CMAKE_CURRENT_LIST_DIR}/Types.h 9 | ) 10 | 11 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../common") 12 | 13 | add_library(PlayerSpy SHARED ${SOURCES}) 14 | target_link_libraries(PlayerSpy RetroSpyCommon) 15 | 16 | if (RS_64BIT EQUAL 1) 17 | target_compile_definitions(PlayerSpy PRIVATE __64BIT__) 18 | endif() 19 | -------------------------------------------------------------------------------- /playerspy/Client.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "Client.h" 18 | 19 | #include "ClientManager.h" 20 | #include "PYServer.h" 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include 31 | 32 | #ifdef _WIN32 33 | /* We are on Windows */ 34 | # define strtok_r strtok_s 35 | #endif 36 | 37 | CClient::CClient(mdk_socket stream, size_t vector_id, CDatabase* db) 38 | { 39 | m_stream = stream; 40 | m_dbConnect = db; 41 | 42 | m_email[0] = m_location[0] = 0; 43 | m_profileid = m_userid = m_sesskey = m_partnerid = 0; 44 | m_sdkversion = 0; 45 | m_port = 0; 46 | m_vector_id = vector_id; 47 | m_status_type = m_quiet_flags = GP_ERROR; 48 | m_SentBuddies = m_SentAddRequests = m_bLogged = false; 49 | 50 | m_ip = CTemplateServer::GetIPFromSocket(stream); 51 | 52 | strncpy(m_status, "Offline", sizeof(m_status)); 53 | m_status[sizeof(m_status) - 1] = '\0'; 54 | } 55 | 56 | CClient::~CClient() 57 | { 58 | Disconnect(); 59 | } 60 | 61 | void CClient::Disconnect() 62 | { 63 | if (m_profileid != 0) 64 | FreeSessionKey(m_dbConnect, m_profileid); 65 | 66 | m_profileid = 0; 67 | m_userid = 0; 68 | m_bLogged = false; 69 | } 70 | 71 | bool CClient::HasBuddy(CClient *c) 72 | { 73 | return HasBuddy(c->GetProfileID()); 74 | } 75 | 76 | bool CClient::HasBuddy(unsigned int id) 77 | { 78 | std::list::iterator iterator = m_buddies.begin(); 79 | unsigned int pid = 0; 80 | 81 | while (iterator != m_buddies.end()) 82 | { 83 | pid = *iterator; 84 | if (id == pid) 85 | return true; 86 | 87 | iterator++; 88 | } 89 | 90 | return false; 91 | } 92 | 93 | bool CClient::HasBlocked(CClient *c) 94 | { 95 | return HasBlocked(c->GetProfileID()); 96 | } 97 | 98 | bool CClient::HasBlocked(unsigned int id) 99 | { 100 | std::list::iterator iterator = m_blocked.begin(); 101 | unsigned int pid = 0; 102 | 103 | while (iterator != m_blocked.end()) 104 | { 105 | pid = *iterator; 106 | 107 | if (pid == id) 108 | return true; 109 | 110 | iterator++; 111 | } 112 | 113 | return false; 114 | } 115 | 116 | void CClient::SendBuddyStatus(CClient *c) 117 | { 118 | SendBuddyInfo(c->GetProfileID()); 119 | } 120 | 121 | bool CClient::ProductInviteable(unsigned int id) 122 | { 123 | std::list::iterator iterator = m_products.begin(); 124 | unsigned int pid = 0; 125 | 126 | while (iterator != m_products.end()) 127 | { 128 | pid = *iterator; 129 | 130 | if (pid == id) 131 | return true; 132 | 133 | iterator++; 134 | } 135 | 136 | return false; 137 | } 138 | 139 | bool CClient::Handle(const char *req, const char *buf, int len) 140 | { 141 | m_lastpacket = time(NULL); 142 | 143 | if (strcmp(req, "login") == 0) 144 | return HandleLogin(buf, len); 145 | else if (strcmp(req, "newuser") == 0) 146 | return HandleNewUser(buf, len); 147 | else if (strcmp(req, "inviteto") == 0) 148 | return HandleInviteTo(buf, len); 149 | 150 | if (m_bLogged == 0) 151 | { 152 | return false; 153 | } 154 | 155 | if (strcmp(req, "logout") == 0) 156 | { 157 | Disconnect(); 158 | return false; 159 | } 160 | else if (strcmp(req, "status") == 0) 161 | return HandleStatus(buf, len); 162 | else if (strcmp(req, "getprofile") == 0) 163 | return HandleGetProfile(buf, len); 164 | else 165 | { 166 | LOG_WARN("PlayerSpy", "Uknown request \"%s\" received!", req); 167 | return false; 168 | } 169 | 170 | return true; 171 | } 172 | 173 | bool CClient::HandleLogin(const char *buf, int) 174 | { 175 | char unick[GP_UNIQUENICK_LEN]; 176 | char user[GP_EMAIL_LEN + GP_NICK_LEN + 2]; 177 | char password[GP_PASSWORD_LEN]; 178 | char sdkver[10]; 179 | char response[33]; 180 | char clientchall[GP_CLIENTCHALL_LEN]; 181 | char authtoken[GP_AUTHTOKEN_LEN]; 182 | char lt[GP_LOGIN_TICKET_LEN]; 183 | char proof[MD5_BUFFER_LEN]; 184 | char sendbuf[1101]; 185 | 186 | response[0] = clientchall[0] = sdkver[0] = unick[0] = user[0] = 0; 187 | lt[0] = authtoken[0] = sendbuf[0] = password[0] = 0; 188 | 189 | // Get data from buffer 190 | if (!get_gs_data(buf, "challenge", clientchall, sizeof(clientchall))) 191 | { 192 | Write("\\error\\err\\266\\fatal\\errmsg\\Invalid client challenge\\final\\"); 193 | return false; 194 | } 195 | 196 | get_gs_data(buf, "uniquenick", unick, sizeof(unick)); 197 | get_gs_data(buf, "user", user, sizeof(user)); 198 | 199 | get_gs_data(buf, "sdkrevision", sdkver, sizeof(sdkver)); 200 | if (sdkver[0] != 0) 201 | m_sdkversion = atoi(sdkver); 202 | 203 | get_gs_data(buf, "port", sdkver, sizeof(sdkver)); 204 | if (sdkver[0] != 0) 205 | m_port = (short)atoi(sdkver); 206 | 207 | get_gs_data(buf, "partnerid", sdkver, sizeof(sdkver)); 208 | if (sdkver[0] != 0) 209 | m_partnerid = atoi(sdkver); 210 | 211 | if ( (user[0] == 0) && (unick[0] == 0) ) 212 | { 213 | 214 | get_gs_data(buf, "authtoken", authtoken, sizeof(authtoken)); 215 | if (authtoken[0] == 0) 216 | { 217 | Write("\\err\\266\\fatal\\errmsg\\Invalid authtoken\\final\\"); 218 | return false; 219 | } 220 | } 221 | 222 | if (authtoken[0] == 0) 223 | { 224 | // Handle partner id proof 225 | if (m_partnerid != GS_PARTNER_ID) 226 | { 227 | if (unick[0] != 0) 228 | snprintf(authtoken, sizeof(authtoken), "%d@%s", m_partnerid, unick); 229 | else 230 | snprintf(authtoken, sizeof(authtoken), "%d@%s", m_partnerid, user); 231 | } 232 | else 233 | { 234 | if (unick[0] != 0) 235 | snprintf(authtoken, sizeof(authtoken), "%s", unick); 236 | else 237 | snprintf(authtoken, sizeof(authtoken), "%s", user); 238 | } 239 | } 240 | 241 | if (unick[0] == 0 && user[0] != 0) 242 | { 243 | // Login with user (nick@email) 244 | 245 | char nick[GP_NICK_LEN], email[GP_EMAIL_LEN]; 246 | 247 | if (!user_to_emailnick(user, email, sizeof(email), nick, sizeof(nick))) 248 | { 249 | Write("\\err\\261\\fatal\\errmsg\\Invalid profile information\\final\\"); 250 | return false; 251 | } 252 | 253 | 254 | if (!GetProfileIDFromNickEmail(m_dbConnect, nick, email, &m_profileid)) 255 | { 256 | Write("\\err\\261\\fatal\\errmsg\\Invalid profile\\final\\"); 257 | return false; 258 | } 259 | 260 | GetUniqueNickFromProfileID(m_dbConnect, m_profileid, unick, sizeof(unick)); 261 | } 262 | else if (user[0] == 0 && unick[0] != 0) 263 | { 264 | // Login with uniquenick 265 | 266 | if (!GetProfileIDFromUniqueNick(m_dbConnect, unick, &m_profileid)) 267 | { 268 | Write("\\err\\261\\fatal\\errmsg\\Invalid profile\\final\\"); 269 | return false; 270 | } 271 | } 272 | else if (authtoken[0] != 0) 273 | { 274 | // Login with authentication token 275 | 276 | if (!GetProfileIDFromAuthToken(m_dbConnect, authtoken, &m_profileid)) 277 | { 278 | Write("\\err\\266\\fatal\\errmsg\\Invalid authtoken\\final\\"); 279 | return false; 280 | } 281 | 282 | GetUniqueNickFromProfileID(m_dbConnect, m_profileid, unick, sizeof(unick)); 283 | } 284 | 285 | // Assign the remaining data key 286 | if (!GetUserIDFromProfileID(m_dbConnect, m_profileid, &m_userid)) 287 | { 288 | Write("\\err\\256\\fatal\\errmsg\\Unable to assign a session key\\final\\"); 289 | return false; 290 | } 291 | 292 | m_sesskey = AssignSessionKeyFromProfileID(m_dbConnect, m_profileid); 293 | GetPasswordFromUserID(m_dbConnect, password, sizeof(password), m_userid); 294 | 295 | // Set login ticket 296 | strrand(sendbuf, GP_LOGIN_TICKET_LEN, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]["); 297 | sendbuf[GP_LOGIN_TICKET_LEN - 3] = '_'; 298 | sendbuf[GP_LOGIN_TICKET_LEN - 2] = '_'; 299 | sendbuf[GP_LOGIN_TICKET_LEN - 1] = '\0'; 300 | strncpy(lt, sendbuf, sizeof(lt)); 301 | lt[sizeof(lt) - 1] = '\0'; 302 | 303 | // Do proof 304 | gs_do_proof(proof, password, authtoken, PYServer::GetServerChallenge(), clientchall); 305 | 306 | snprintf(sendbuf, sizeof(sendbuf), 307 | "\\lc\\2\\sesskey\\%d\\proof\\%s\\userid\\%u\\profileid\\%u" 308 | "\\uniquenick\\%s\\lt\\%s\\id\\%d\\final\\", m_sesskey, proof, 309 | m_userid, m_profileid, unick, lt, PYServer::GetServerID()); 310 | 311 | Write(sendbuf); 312 | 313 | LoadBuddies(); 314 | LoadBlockedList(); 315 | SendMessages(); 316 | 317 | if (m_sdkversion & GPI_NEW_LIST_RETRIEVAL_ON_LOGIN) 318 | SendBuddies(); 319 | 320 | m_bLogged = true; 321 | 322 | return true; 323 | } 324 | 325 | bool CClient::HandleInviteTo(const char *buf, int) 326 | { 327 | char products[256]; 328 | int pdo = 0; 329 | char *pch = NULL, *ctx = NULL; 330 | 331 | if (!get_gs_data(buf, "products", products, sizeof(products))) 332 | return false; 333 | 334 | m_products.clear(); 335 | 336 | if (strcmp(products, "") == 0) 337 | return true; 338 | 339 | if (strchr(products, '\\') != NULL) 340 | { 341 | pch = strtok_r(products, ",", &ctx); 342 | 343 | while (pch != NULL) 344 | { 345 | pdo = atoi(pch); 346 | m_products.push_front(pdo); 347 | //pch = strtok(pch, ","); 348 | pch = strtok_r(NULL, ",", &ctx); // TODO: Finish this 349 | } 350 | } 351 | else 352 | { 353 | pdo = atoi(products); 354 | m_products.push_front(pdo); 355 | } 356 | 357 | return true; 358 | } 359 | 360 | bool CClient::HandleNewUser(const char *buf, int) 361 | { 362 | LOG_ERROR("PlayerSpy", "Received body for HandleNewUser: %s!", buf); 363 | LOG_INFO("PlayerSpy", "Please report this message (inclusing the body) to any contributor!"); 364 | 365 | return false; 366 | } 367 | 368 | void CClient::SendBuddyInfo(unsigned int id) 369 | { 370 | CClient *c = CClientManager::GetFromProfileID(id); 371 | char statstr[GP_STATUS_STRING_LEN + GP_STATUS_STRING_LEN + 128 + 60]; 372 | 373 | if (c == NULL || c->HasBlocked(m_profileid)) 374 | snprintf(statstr, sizeof(statstr), "\\bm\\%d\\f\\%u\\msg\\|s|0|ss|Offline\\final\\", GPI_BM_STATUS, m_profileid); 375 | else 376 | { 377 | snprintf(statstr, sizeof(statstr), "\\bm\\%d\\f\\%u\\|s|%d|ss|%s%s%s|ip|%d|p|%d|gm|%d\\final\\", 378 | GPI_BM_STATUS, m_profileid, c->GetStatusType(), c->GetStatus(), c->GetLocation()[0] != 0 ? "|ls|" : "", c->GetLocation(), 379 | reverse_endian32(c->GetIP()), reverse_endian16(c->GetPort()), c->GetQuietFlags()); 380 | } 381 | 382 | Write(statstr); 383 | } 384 | 385 | 386 | // Operators 387 | bool CClient::operator==(CClient& c) 388 | { 389 | if ( (GetProfileID() == c.GetProfileID()) && (GetUserID() == c.GetUserID()) ) 390 | return true; 391 | 392 | return false; 393 | } 394 | 395 | bool CClient::operator!=(CClient& c) 396 | { 397 | if ( (GetProfileID() != c.GetProfileID()) || (GetUserID() != c.GetUserID()) ) 398 | return true; 399 | 400 | return false; 401 | } 402 | 403 | void CClient::Write(std::string str) 404 | { 405 | CTemplateSocket::WriteTCP(m_stream, str); 406 | } 407 | 408 | void CClient::Write(const char *str) 409 | { 410 | CTemplateSocket::WriteTCP(m_stream, str); 411 | } 412 | 413 | bool CClient::HandleStatus(const char *buf, int) 414 | { 415 | get_gs_data(buf, "statstring", m_status, sizeof(m_status)); 416 | get_gs_data(buf, "locstring", m_location, sizeof(m_location)); 417 | 418 | if (!m_SentBuddies) 419 | SendBuddies(); 420 | 421 | if (!m_SentAddRequests) 422 | SendAddRequests(); 423 | 424 | CClientManager::SendUpdateStatus(this); 425 | return true; 426 | } 427 | 428 | void CClient::SendBuddies() 429 | { 430 | std::list::iterator it; 431 | unsigned int pid = 0; 432 | 433 | m_SentBuddies = true; 434 | 435 | //if (m_sdkversion & GPI_NEW_LIST_RETRIEVAL_ON_LOGIN) 436 | //{ 437 | std::string str = ""; 438 | char txp[16]; 439 | 440 | snprintf(txp, sizeof(txp), "%zu", m_buddies.size()); 441 | 442 | it = m_buddies.begin(); 443 | 444 | str = "\\bdy\\"; 445 | str += txp; 446 | str += "\\list\\"; 447 | 448 | while (it != m_buddies.end()) 449 | { 450 | pid = *it; 451 | 452 | snprintf(txp, sizeof(txp), "%u", pid); 453 | 454 | str += txp; 455 | 456 | it++; 457 | 458 | if (it != m_buddies.end()) 459 | { 460 | str += ","; 461 | } 462 | } 463 | 464 | str += "\\final\\"; 465 | 466 | Write(str); 467 | 468 | 469 | it = m_buddies.begin(); 470 | 471 | while (it != m_buddies.end()) 472 | { 473 | pid = *it; 474 | SendBuddyInfo(pid); 475 | it++; 476 | } 477 | //} 478 | } 479 | 480 | void CClient::SendAddRequests() 481 | { 482 | char query[256]; 483 | CResultSet *res = new CResultSet(); 484 | std::string str = ""; 485 | 486 | query[0] = 0; 487 | 488 | snprintf(query, sizeof(query), "SELECT `profileid`, `syncrequested`, `reason` FROM `addrequests` WHERE `targetid`=%u", m_profileid); 489 | if (!res->ExecuteQuery(m_dbConnect, query)) 490 | { 491 | delete res; 492 | return; 493 | } 494 | if (!res->GotoFirstRow()) 495 | { 496 | delete res; 497 | return; 498 | } 499 | 500 | m_SentAddRequests = true; 501 | 502 | do 503 | { 504 | str = "\\bm\\"; 505 | snprintf(query, sizeof(query), "%d", GPI_BM_REQUEST); 506 | str += query; 507 | str += "\\f\\"; 508 | str += res->GetStringFromRow(0); 509 | str += "\\msg\\"; 510 | str += res->GetStringFromRow(1); 511 | str += "|signed|"; 512 | str += res->GetStringFromRow(2); 513 | str += "\\final\\"; 514 | 515 | Write(str); 516 | } while (res->GotoNextRow()); 517 | 518 | delete res; 519 | } 520 | 521 | void CClient::LoadBuddies() 522 | { 523 | char query[128]; 524 | CResultSet *res = new CResultSet(); 525 | 526 | query[0] = 0; 527 | 528 | m_buddies.clear(); 529 | 530 | snprintf(query, sizeof(query), 531 | "SELECT `targetid` FROM `friends` WHERE `profileid`=%u", m_profileid); 532 | 533 | if (!res->ExecuteQuery(m_dbConnect, query)) 534 | { 535 | delete res; 536 | return; 537 | } 538 | 539 | if (!res->GotoFirstRow()) 540 | { 541 | delete res; 542 | return; 543 | } 544 | 545 | do 546 | { 547 | m_buddies.push_front(res->GetUIntFromRow(0)); 548 | } while (res->GotoNextRow()); 549 | 550 | delete res; 551 | } 552 | 553 | void CClient::LoadBlockedList() 554 | { 555 | char query[128]; 556 | CResultSet *res = new CResultSet(); 557 | 558 | query[0] = 0; 559 | 560 | snprintf(query, sizeof(query), 561 | "SELECT `targetid` FROM `blocked` WHERE `profileid`=%u", m_profileid); 562 | 563 | if (!res->ExecuteQuery(m_dbConnect, query)) 564 | { 565 | delete res; 566 | return; 567 | } 568 | 569 | if (!res->GotoFirstRow()) 570 | { 571 | delete res; 572 | return; 573 | } 574 | 575 | m_blocked.clear(); 576 | 577 | do 578 | { 579 | m_blocked.push_front(res->GetIntFromRow(0)); 580 | } while (res->GotoNextRow()); 581 | 582 | delete res; 583 | } 584 | 585 | void CClient::SendMessages() 586 | { 587 | char query[256]; 588 | CResultSet *res = new CResultSet(); 589 | std::string str = ""; 590 | 591 | query[0] = 0; 592 | 593 | if (m_dbConnect->GetDatabaseType() == DATABASE_TYPE_MARIADB) 594 | snprintf(query, sizeof(query), "SELECT `message`, `from`, Unix_Timestamp(`date`) FROM `messages` WHERE `to`=%u", m_profileid); 595 | else if (m_dbConnect->GetDatabaseType() == DATABASE_TYPE_SQLITE) 596 | snprintf(query, sizeof(query), "SELECT `message`, `from`, `date` FROM `messages` WHERE `to`=%u", m_profileid); 597 | 598 | if (!res->ExecuteQuery(m_dbConnect, query)) 599 | { 600 | delete res; 601 | return; 602 | } 603 | 604 | if (!res->GotoFirstRow()) 605 | { 606 | delete res; 607 | return; 608 | } 609 | 610 | do 611 | { 612 | snprintf(query, sizeof(query), "%d", GPI_BM_MESSAGE); 613 | 614 | str = "\\bm\\"; 615 | str += query; 616 | str += "\\f\\"; 617 | str += res->GetStringFromRow(1); 618 | str += "\\date\\"; 619 | str += res->GetStringFromRow(2); 620 | str += "\\msg\\"; 621 | str += res->GetStringFromRow(0); 622 | str += "\\final\\"; 623 | Write(str); 624 | } while (res->GotoNextRow()); 625 | 626 | delete res; 627 | 628 | snprintf(query, sizeof(query), "DELETE FROM `messages` WHERE `to`=%u", m_profileid); 629 | mdk_only_run_query(m_dbConnect, query); 630 | } 631 | 632 | bool CClient::HandleGetProfile(const char *buf, int) 633 | { 634 | std::string str = "\\pi\\profileid\\"; 635 | char txp[101]; 636 | char sign[MD5_BUFFER_LEN]; 637 | int id = 0; 638 | unsigned int pid = 0; 639 | unsigned int uid = 0; 640 | GPIInfoCache info; 641 | 642 | if (!m_SentBuddies) 643 | SendBuddies(); 644 | 645 | if (!get_gs_data(buf, "id", txp, sizeof(txp))) 646 | return false; 647 | 648 | id = atoi(txp); 649 | 650 | if (!get_gs_data(buf, "profileid", txp, sizeof(txp))) 651 | return false; 652 | 653 | str += txp; 654 | pid = atoi(txp); 655 | 656 | str += "\\userid\\"; 657 | 658 | if (!GetProfileInfo(m_dbConnect, pid, &info, &uid)) 659 | return false; 660 | 661 | snprintf(txp, sizeof(txp), "%u", uid); 662 | str += txp; 663 | 664 | str += "\\nick\\"; 665 | str += info.nick; 666 | str += "\\uniquenick\\"; 667 | str += info.uniquenick; 668 | 669 | if (info.publicmask & GP_MASK_EMAIL) 670 | { 671 | str += "\\email\\"; 672 | str += info.email; 673 | } 674 | 675 | str += "\\firstname\\"; 676 | str += info.firstname; 677 | str += "\\lastname\\"; 678 | str += info.lastname; 679 | 680 | if (info.publicmask & GP_MASK_COUNTRYCODE) 681 | { 682 | str += "\\countrycode\\"; 683 | str += info.countrycode; 684 | } 685 | 686 | str += "\\aim\\"; 687 | str += info.aimname; 688 | 689 | str += "\\pmask\\"; 690 | snprintf(txp, sizeof(txp), "%d", info.publicmask); 691 | str += txp; 692 | 693 | str += "\\pic\\"; 694 | snprintf(txp, sizeof(txp), "%d", info.pic); 695 | str += txp; 696 | 697 | str += "\\ooc\\"; 698 | snprintf(txp, sizeof(txp), "%d", info.occupationid); 699 | str += txp; 700 | 701 | str += "\\ind\\"; 702 | snprintf(txp, sizeof(txp), "%d", info.industryid); 703 | str += txp; 704 | 705 | str += "\\inc\\"; 706 | snprintf(txp, sizeof(txp), "%d", info.incomeid); 707 | str += txp; 708 | 709 | str += "\\mar\\"; 710 | snprintf(txp, sizeof(txp), "%d", info.marriedid); 711 | str += txp; 712 | 713 | str += "\\chc\\"; 714 | snprintf(txp, sizeof(txp), "%d", info.childcount); 715 | str += txp; 716 | 717 | str += "\\i1\\"; 718 | snprintf(txp, sizeof(txp), "%d", info.interests1); 719 | str += txp; 720 | 721 | str += "\\o1\\"; 722 | snprintf(txp, sizeof(txp), "%d", info.ownership1); 723 | str += txp; 724 | 725 | str += "\\conn\\"; 726 | snprintf(txp, sizeof(txp), "%d", info.conntypeid); 727 | str += txp; 728 | 729 | if (info.publicmask & GP_MASK_SEX) 730 | { 731 | str += "\\sex\\"; 732 | snprintf(txp, sizeof(txp), "%d", info.sex); 733 | str += txp; 734 | } 735 | 736 | if (info.publicmask & GP_MASK_ZIPCODE) 737 | { 738 | str += "\\zipcode\\"; 739 | str += info.zipcode; 740 | } 741 | 742 | if (info.publicmask & GP_MASK_HOMEPAGE) 743 | { 744 | str += "\\homepage\\"; 745 | str += info.homepage; 746 | } 747 | 748 | if (info.publicmask & GP_MASK_BIRTHDAY) 749 | { 750 | int bdd = 0; 751 | 752 | bdd |= (info.birthday << 24); 753 | bdd |= (info.birthmonth << 16); 754 | bdd |= info.birthyear; 755 | 756 | str += "\\birthday\\"; 757 | snprintf(txp, sizeof(txp), "%d", bdd); 758 | str += txp; 759 | } 760 | 761 | str += "\\lon\\"; 762 | snprintf(txp, sizeof(txp), "%f", info.longitude); 763 | str += txp; 764 | 765 | str += "\\lat\\"; 766 | snprintf(txp, sizeof(txp), "%f", info.latitude); 767 | str += txp; 768 | 769 | str += "\\loc\\"; 770 | str += info.place; 771 | 772 | hash_md5(str.c_str(), str.length(), sign); 773 | 774 | str += "\\sig\\"; 775 | str += sign; 776 | 777 | str += "\\id\\"; 778 | snprintf(txp, sizeof(txp), "%d", id); 779 | str += txp; 780 | 781 | // Old support 782 | str += "\\mp\\4\\st\\"; 783 | 784 | str += "\\final\\"; 785 | 786 | Write(str); 787 | return true; 788 | } 789 | -------------------------------------------------------------------------------- /playerspy/Client.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef PY_CLIENT_H 18 | #define PY_CLIENT_H 19 | 20 | #include 21 | #include 22 | 23 | #include "Types.h" 24 | 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | class CClient 33 | { 34 | public: 35 | CClient(mdk_socket stream, size_t vector_id, CDatabase* db); 36 | ~CClient(); 37 | 38 | bool HasBuddy(CClient *c); 39 | bool HasBuddy(unsigned int id); 40 | 41 | bool HasBlocked(CClient *c); 42 | bool HasBlocked(unsigned int id); 43 | 44 | void SendBuddyStatus(CClient *c); 45 | 46 | bool ProductInviteable(unsigned int pid); 47 | 48 | bool Handle(const char *req, const char *buf, int len); 49 | 50 | inline unsigned int GetUserID() { return m_userid; } 51 | inline unsigned int GetProfileID() { return m_profileid; } 52 | 53 | inline time_t GetLastPacket() { return m_lastpacket; } 54 | 55 | inline int GetPartnerID() { return m_partnerid; } 56 | 57 | inline short GetPort() { return m_port; } 58 | inline int GetIP() { return m_ip; } 59 | 60 | inline int GetSDKVersion() { return m_sdkversion; } 61 | 62 | inline GPEnum GetStatusType() { return m_status_type; } 63 | inline const char *GetStatus() { return m_status; } 64 | 65 | inline GPEnum GetQuietFlags() { return m_quiet_flags; } 66 | 67 | inline const char *GetLocation() { return m_location; } 68 | 69 | inline mdk_socket GetSocket() { return m_stream; } 70 | 71 | inline size_t GetVectorID() { return m_vector_id; } 72 | 73 | void Disconnect(); 74 | 75 | // Operator overload 76 | bool operator==(CClient& c); 77 | bool operator!=(CClient& c); 78 | 79 | private: 80 | char m_email[GP_EMAIL_LEN]; 81 | 82 | unsigned int m_profileid; 83 | unsigned int m_userid; 84 | 85 | unsigned int m_sesskey; 86 | 87 | size_t m_vector_id; 88 | 89 | mdk_socket m_stream; 90 | 91 | int m_sdkversion; 92 | 93 | int m_partnerid; 94 | 95 | short m_port; 96 | int m_ip; 97 | 98 | time_t m_lastpacket; 99 | 100 | GPEnum m_status_type; 101 | char m_status[GP_STATUS_STRING_LEN]; 102 | 103 | GPEnum m_quiet_flags; 104 | 105 | char m_location[GP_STATUS_STRING_LEN]; 106 | 107 | bool m_SentBuddies; 108 | bool m_SentAddRequests; 109 | bool m_bLogged; 110 | 111 | std::list m_blocked; 112 | std::list m_buddies; 113 | std::list m_products; 114 | 115 | private: 116 | bool HandleLogin(const char *buf, int len); 117 | bool HandleInviteTo(const char *buf, int len); 118 | bool HandleNewUser(const char *buf, int len); 119 | bool HandleStatus(const char *buf, int len); 120 | bool HandleGetProfile(const char *buf, int len); 121 | 122 | void SendBuddyInfo(unsigned int id); 123 | void SendBuddies(); 124 | void SendAddRequests(); 125 | 126 | void LoadBuddies(); 127 | void LoadBlockedList(); 128 | 129 | void SendMessages(); 130 | 131 | void Write(const char *str); 132 | void Write(std::string str); 133 | 134 | CDatabase* m_dbConnect; 135 | }; 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /playerspy/ClientManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "ClientManager.h" 18 | 19 | #include 20 | 21 | void CClientManager::Free() 22 | { 23 | ClientMap::iterator it = m_clients.begin(); 24 | 25 | while (it != m_clients.end()) 26 | { 27 | // Free CClient memory 28 | if (it->second) 29 | delete it->second; 30 | 31 | it++; 32 | } 33 | 34 | m_clients.clear(); 35 | } 36 | 37 | void CClientManager::Delete(ClientMap::iterator it) 38 | { 39 | CTemplateServer* server = NULL; 40 | 41 | if (it == m_clients.end()) 42 | return; 43 | 44 | if (!it->second) 45 | return; 46 | 47 | CTemplateSocket::GetSocketExtraData(it->second->GetSocket())->SetData(NULL); 48 | 49 | delete (it->second); 50 | 51 | m_clients.erase(it); 52 | } 53 | 54 | bool CClientManager::CreateAndHandle(CDatabase* db, mdk_socket stream, const char *req, const char *buf, ssize_t len) 55 | { 56 | // Create che client 57 | ClientMap::iterator it; 58 | CClient* c = NULL; 59 | size_t i = m_clients.size(); 60 | 61 | m_clients[i] = new CClient(stream, i, db); 62 | 63 | it = m_clients.begin(); 64 | std::advance(it, i); 65 | 66 | c = it->second; 67 | 68 | CTemplateSocket::GetSocketExtraData(stream)->SetData((void*)c->GetVectorID()); 69 | 70 | if (!c->Handle(req, buf, len)) 71 | { 72 | Delete(it); // Delete the client if it returned false 73 | return false; 74 | } 75 | 76 | return true; 77 | } 78 | 79 | bool CClientManager::Handle(CDatabase* con, mdk_socket stream, const char *req, const char*buf, ssize_t len) 80 | { 81 | ClientMap::iterator it; 82 | unsigned int i = 0; 83 | 84 | if (CTemplateSocket::GetSocketExtraData(stream)->GetData() == NULL) 85 | return CreateAndHandle(con, stream, req, buf, len); // Create the instance 86 | 87 | it = m_clients.find((size_t)CTemplateSocket::GetSocketExtraData(stream)->GetData()); 88 | 89 | if (it == m_clients.end()) 90 | return false; 91 | 92 | // Handle our client 93 | if (!it->second->Handle(req, buf, len)) 94 | { 95 | Delete(it); // Delete the client if it returned false 96 | return false; 97 | } 98 | 99 | return true; 100 | } 101 | 102 | CClient * CClientManager::GetFromProfileID(unsigned int id) 103 | { 104 | ClientMap::iterator it = m_clients.begin(); 105 | 106 | while (it != m_clients.end()) 107 | { 108 | if (it->second->GetProfileID() == id) 109 | return it->second; 110 | 111 | it++; 112 | } 113 | 114 | return NULL; 115 | } 116 | 117 | void CClientManager::SendUpdateStatus(CClient *c) 118 | { 119 | ClientMap::iterator it = m_clients.begin(); 120 | 121 | while (it != m_clients.end()) 122 | { 123 | CClient *cc = it->second; 124 | 125 | if (cc->HasBuddy(c)) 126 | cc->SendBuddyStatus(c); 127 | 128 | it++; 129 | } 130 | } 131 | 132 | ClientMap CClientManager::m_clients; 133 | -------------------------------------------------------------------------------- /playerspy/ClientManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef PY_CLIENTMANAGER_H 18 | #define PY_CLIENTMANAGER_H 19 | 20 | #include "Client.h" 21 | 22 | #include 23 | 24 | #include 25 | 26 | typedef std::map ClientMap; 27 | 28 | class CClientManager 29 | { 30 | public: 31 | static bool Handle(CDatabase* db, mdk_socket stream, const char *req, const char*buf, ssize_t len); 32 | static void Free(); 33 | 34 | static CClient *GetFromProfileID(unsigned int id); 35 | 36 | static void SendUpdateStatus(CClient *c); 37 | 38 | private: 39 | static ClientMap m_clients; 40 | 41 | private: 42 | static void Delete(ClientMap::iterator ss); 43 | static bool CreateAndHandle(CDatabase* db, mdk_socket stream, const char *req, const char *buf, ssize_t len); 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /playerspy/PYServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "PYServer.h" 18 | 19 | #include "ClientManager.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #ifdef _WIN32 30 | #define strcasecmp _stricmp 31 | #endif 32 | 33 | PYServer::PYServer(int defaultport, bool ip) : CTemplateStringServer(defaultport, ip) {} 34 | 35 | int PYServer::Initialize() 36 | { 37 | if (!m_lpDatabase) 38 | return ERROR_DATABASE_ERROR; 39 | 40 | PYServer::server_id = 1; 41 | strrand(PYServer::server_challenge, sizeof(PYServer::server_challenge), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 42 | 43 | return ERROR_NONE; 44 | } 45 | 46 | PYServer::~PYServer() 47 | { 48 | CClientManager::Free(); 49 | } 50 | 51 | bool PYServer::HandleRequest(mdk_socket stream, const char *req, const char *buf, int size) 52 | { 53 | if (strcasecmp(req, "ka") == 0) 54 | { 55 | // Keep-Alive 56 | WriteTCP(stream, "\\ka\\final\\"); 57 | return true; 58 | } 59 | else if (strcasecmp(req, "newuser") == 0) 60 | { 61 | return HandleNewUser(stream, buf, size); 62 | } 63 | 64 | if (!CClientManager::Handle(m_lpDatabase, stream, req, buf, size)) 65 | { 66 | return false; 67 | } 68 | 69 | return true; 70 | } 71 | 72 | bool PYServer::HandleNewUser(mdk_socket stream, const char* buf, int size) 73 | { 74 | char nick[GP_NICK_LEN], email[GP_EMAIL_LEN], pass[GP_PASSWORD_LEN], passenc[GP_PASSWORDENC_LEN], unick[GP_UNIQUENICK_LEN]; 75 | 76 | pass[0] = nick[0] = email[0] = passenc[0] = unick[0] = '\0'; 77 | 78 | 79 | if (!get_gs_data(buf, "uniquenick", unick, GP_UNIQUENICK_LEN)) 80 | return false; 81 | 82 | if (!get_gs_data(buf, "email", email, GP_EMAIL_LEN)) 83 | return false; 84 | 85 | if (!get_gs_data(buf, "nick", nick, GP_NICK_LEN)) 86 | return false; 87 | 88 | if (!get_gs_data(buf, "passenc", passenc, GP_PASSWORDENC_LEN)) 89 | return false; 90 | 91 | gs_pass_decode(passenc, pass); 92 | 93 | 94 | 95 | return true; 96 | } 97 | 98 | bool PYServer::OnTCPNewConnection(mdk_socket stream, int) 99 | { 100 | char fch[45]; 101 | fch[0] = 0; 102 | 103 | snprintf(fch, sizeof(fch), "\\lc\\1\\challenge\\%s\\id\\%d\\final\\", server_challenge, server_id); 104 | 105 | WriteTCP(stream, fch); 106 | return true; 107 | 108 | } 109 | 110 | int PYServer::GetServerID() 111 | { 112 | return server_id; 113 | } 114 | 115 | const char *PYServer::GetServerChallenge() 116 | { 117 | return server_challenge; 118 | } 119 | 120 | int PYServer::server_id = 0; 121 | char PYServer::server_challenge[GP_SERVERCHALL_LEN] = {0}; 122 | 123 | ModuleEntryPoint(PYServer, 29900, false) 124 | -------------------------------------------------------------------------------- /playerspy/PYServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef GPCMSERVER_H 18 | #define GPCMSERVER_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | /* 25 | This class rappresents a Player Search server 26 | */ 27 | class PYServer : public CTemplateStringServer 28 | { 29 | public: 30 | PYServer(int defaultport, bool udp); 31 | ~PYServer(); 32 | 33 | int Initialize(); 34 | 35 | /* See CServer::OnNewConnection */ 36 | bool OnTCPNewConnection(mdk_socket stream, int status); 37 | 38 | /* See CStringServer::HandleRequest */ 39 | bool HandleRequest(mdk_socket stream, const char *req, const char *buf, int size); 40 | 41 | static int GetServerID(); 42 | static const char *GetServerChallenge(); 43 | 44 | private: 45 | static char server_challenge[GP_SERVERCHALL_LEN]; 46 | static int server_id; 47 | 48 | bool HandleNewUser(mdk_socket stream, const char* buf, int size); 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /playerspy/Types.h: -------------------------------------------------------------------------------- 1 | /* 2 | BSD 3-Clause License 3 | 4 | Copyright (c) 2017, GameProgressive Team 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | #ifndef PY_TYPES_H 33 | #define PY_TYPES_H 34 | 35 | // Types of bm's. 36 | ///////////////// 37 | #define GPI_BM_MESSAGE 1 38 | #define GPI_BM_REQUEST 2 39 | #define GPI_BM_REPLY 3 // only used on the backend 40 | #define GPI_BM_AUTH 4 41 | #define GPI_BM_UTM 5 42 | #define GPI_BM_REVOKE 6 // remote buddy removed from local list 43 | #define GPI_BM_STATUS 100 44 | #define GPI_BM_INVITE 101 45 | #define GPI_BM_PING 102 46 | #define GPI_BM_PONG 103 47 | #define GPI_BM_KEYS_REQUEST 104 48 | #define GPI_BM_KEYS_REPLY 105 49 | #define GPI_BM_FILE_SEND_REQUEST 200 50 | #define GPI_BM_FILE_SEND_REPLY 201 51 | #define GPI_BM_FILE_BEGIN 202 52 | #define GPI_BM_FILE_END 203 53 | #define GPI_BM_FILE_DATA 204 54 | #define GPI_BM_FILE_SKIP 205 55 | #define GPI_BM_FILE_TRANSFER_THROTTLE 206 56 | #define GPI_BM_FILE_TRANSFER_CANCEL 207 57 | #define GPI_BM_FILE_TRANSFER_KEEPALIVE 208 58 | 59 | // Extended message support 60 | #define GPI_NEW_AUTH_NOTIFICATION (1<<0) 61 | #define GPI_NEW_REVOKE_NOTIFICATION (1<<1) 62 | 63 | // New Status Info support 64 | #define GPI_NEW_STATUS_NOTIFICATION (1<<2) 65 | 66 | // Buddy List + Block List retrieval on login 67 | #define GPI_NEW_LIST_RETRIEVAL_ON_LOGIN (1<<3) 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /queryreport2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | ${CMAKE_CURRENT_LIST_DIR}/QR2Server.h 3 | ${CMAKE_CURRENT_LIST_DIR}/QR2Server.cpp 4 | ) 5 | 6 | 7 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../common") 8 | 9 | add_library(QueryReport2 SHARED ${SOURCES}) 10 | target_link_libraries(QueryReport2 RetroSpyCommon) 11 | -------------------------------------------------------------------------------- /queryreport2/QR2Server.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #include "QR2Server.h" 18 | 19 | #define PACKET_TYPE 0x09 20 | 21 | #include 22 | #include 23 | 24 | QR2Server::QR2Server(int defaultport, bool udp) : CThreadServer(defaultport, udp) {} 25 | 26 | QR2Server::~QR2Server() 27 | { 28 | } 29 | 30 | void QR2Server::OnUDPRead(mdk_socket client, const struct sockaddr* addr, const char *data, ssize_t size) 31 | { 32 | unsigned char newdata[7]; 33 | 34 | if (size < 6) 35 | return; 36 | 37 | if (data[0]!=PACKET_TYPE) 38 | return; 39 | 40 | // Packet check 41 | newdata[0] = 0xFE; 42 | newdata[1] = 0xFD; 43 | newdata[2] = 0x09; 44 | 45 | // Status check (int=sizeof(4)) 46 | newdata[3] = 0x00; //0x00 if avaiable, 0x01 if unavaible, 0x02 if unavaiable temporarily 47 | newdata[4] = 0x00; 48 | newdata[5] = 0x00; 49 | newdata[6] = 0x00; 50 | 51 | WriteUDP(client, newdata, sizeof(newdata), addr); 52 | } 53 | 54 | int QR2Server::Initialize() 55 | { 56 | if (!m_lpDatabase) 57 | return ERROR_DATABASE_ERROR; 58 | 59 | return ERROR_NONE; 60 | } 61 | 62 | ModuleEntryPoint(QR2Server, 27900, true) 63 | -------------------------------------------------------------------------------- /queryreport2/QR2Server.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroSpy Server. 3 | 4 | RetroSpy Server is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | RetroSpy Server is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with RetroSpy Server. If not, see . 16 | */ 17 | #ifndef QR2SERVER_H 18 | #define QR2SERVER_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | /* 25 | This class rappresents a Query Report 2 Server 26 | */ 27 | class QR2Server : public CThreadServer 28 | { 29 | public: 30 | QR2Server(int defaultport, bool udp); 31 | ~QR2Server(); 32 | 33 | int Initialize(); 34 | 35 | /* See CServer::OnNewConnection */ 36 | bool OnTCPNewConnection(mdk_socket stream, int status) { return true; } 37 | 38 | void OnTCPRead(mdk_socket client, const char *data, ssize_t size) {} 39 | void OnUDPRead(mdk_socket client, const struct sockaddr* addr, const char *data, ssize_t size); 40 | }; 41 | 42 | #endif 43 | --------------------------------------------------------------------------------