arezey

sv_ip2c.cpp

Dec 28th, 2012
184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.19 KB | None | 0 0
  1. //-----------------------------------------------------------------------------
  2. //
  3. // Zandronum Source
  4. // Copyright (C) 2012 Santeri `Dusk` Piippo
  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. // 1. Redistributions of source code must retain the above copyright notice,
  11. //    this list of conditions and the following disclaimer.
  12. // 2. Redistributions in binary form must reproduce the above copyright notice,
  13. //    this list of conditions and the following disclaimer in the documentation
  14. //    and/or other materials provided with the distribution.
  15. // 3. Neither the name of the Skulltag Development Team nor the names of its
  16. //    contributors may be used to endorse or promote products derived from this
  17. //    software without specific prior written permission.
  18. // 4. Redistributions in any form must be accompanied by information on how to
  19. //    obtain complete source code for the software and any accompanying
  20. //    software that uses the software. The source code must either be included
  21. //    in the distribution or be available for no more than the cost of
  22. //    distribution plus a nominal fee, and must be freely redistributable
  23. //    under reasonable conditions. For an executable file, complete source
  24. //    code means the source code for all modules it contains. It does not
  25. //    include source code for modules or files that typically accompany the
  26. //    major components of the operating system on which the executable file
  27. //    runs.
  28. //
  29. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  30. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  33. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  34. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  35. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  36. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  37. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  38. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  39. // POSSIBILITY OF SUCH DAMAGE.
  40. //
  41. // Filename: sv_ip2c.cpp
  42. //
  43. // Description: IP2C CSV database parsing, storing and accessing functionality.
  44. //
  45. //-----------------------------------------------------------------------------
  46.  
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <stdint.h>
  50. #include <string.h>
  51. #include <assert.h>
  52. #include "i_system.h"
  53. #include "c_cvars.h"
  54. #include "sv_ip2c.h"
  55. #include "network.h"
  56. #include "networkshared.h"
  57. #include "c_dispatch.h"
  58.  
  59. #define MAX_ENTRIES 150000
  60.  
  61. CUSTOM_CVAR (Bool, sv_ip2c, true, CVAR_ARCHIVE) {
  62.     if (self)
  63.         IP2C::LoadDB ();
  64.     else
  65.         IP2C::UnloadDB ();
  66. }
  67.  
  68. CUSTOM_CVAR (String, sv_ip2c_dbfile, "IpToCountry.csv", CVAR_ARCHIVE) {
  69.     // If we change location of the DB file, try
  70.     // load the DB from the new path.
  71.     if (sv_ip2c) {
  72.         IP2C::UnloadDB ();
  73.         IP2C::LoadDB ();
  74.     }
  75. }
  76.  
  77. namespace IP2C {
  78.     typedef struct {
  79.         ULONG minIP;
  80.         const Country_t* country;
  81.     } link_t;
  82.    
  83.     // IPLinks is dynamically allocated so that the database is not allocated if
  84.     // sv_ip2c is false. The database needs over a megabyte of memory!
  85.     static link_t* IPLinks;
  86.    
  87.     static bool IP2CReady = false;
  88.     static const char* ErrorMsg;
  89.     static unsigned long int entryCount = 0;
  90.    
  91.     const Country_t* Localhost = NULL;
  92.     const Country_t* LocalNetwork = NULL;
  93.     const Country_t* PlayerCountries[MAXPLAYERS] = {NULL};
  94.    
  95.     const Country_t CountryData[] = {
  96.         {"ABW", "Aruba"},
  97.         {"AFG", "Afghanistan"},
  98.         {"AFR", "Asia"},
  99.         {"AGO", "Angola"},
  100.         {"AIA", "Anguilla"},
  101.         {"ALA", "Aland Islands"},
  102.         {"ALB", "Albania"},
  103.         {"AND", "Andorra"},
  104.         {"ANT", "Antilles"},
  105.         {"ARE", "United Arab Emirates"},
  106.         {"ARG", "Argentina"},
  107.         {"ARM", "Armenia"},
  108.         {"ASM", "American Samoa"},
  109.         {"ATG", "Antigua and Barbuda"},
  110.         {"AUS", "Australia"},
  111.         {"AUT", "Austria"},
  112.         {"AZE", "Azerbaijan"},
  113.         {"BDI", "Burundi"},
  114.         {"BEL", "Belgium"},
  115.         {"BEN", "Benin"},
  116.         {"BES", "Bonaire"},
  117.         {"BFA", "Burkina Faso"},
  118.         {"BGD", "Bangladesh"},
  119.         {"BGR", "Bulgaria"},
  120.         {"BHR", "Bahrain"},
  121.         {"BHS", "Bahamas"},
  122.         {"BIH", "Bosnia and Herzegowina"},
  123.         {"BLR", "Belarus"},
  124.         {"BLZ", "Belize"},
  125.         {"BMU", "Bermuda"},
  126.         {"BOL", "Bolivia"},
  127.         {"BRA", "Brazil"},
  128.         {"BRB", "Barbados"},
  129.         {"BRN", "Brunei"},
  130.         {"BTN", "Bhutan"},
  131.         {"BWA", "Botswana"},
  132.         {"CAF", "Central Africa"},
  133.         {"CAN", "Canada"},
  134.         {"CHE", "Switzerland"},
  135.         {"CHL", "Chile"},
  136.         {"CHN", "China"},
  137.         {"CIV", "Ivory Coast"},
  138.         {"CMR", "Cameroon"},
  139.         {"COD", "Congo-Kinshasa"},
  140.         {"COG", "Congo-Brazzaville"},
  141.         {"COK", "Cook Islands"},
  142.         {"COL", "Colombia"},
  143.         {"COM", "Comoros"},
  144.         {"CPV", "Cape Verde"},
  145.         {"CRI", "Costa Rica"},
  146.         {"CUB", "Cuba"},
  147.         {"CUW", "Curacao"},
  148.         {"CYM", "Cayman Islands"},
  149.         {"CYP", "Cyprus"},
  150.         {"CZE", "Czech Republic"},
  151.         {"DEU", "Germany"},
  152.         {"DJI", "Djibouti"},
  153.         {"DMA", "Dominica"},
  154.         {"DNK", "Denmark"},
  155.         {"DOM", "Dominican Republic"},
  156.         {"DZA", "Algeria"},
  157.         {"ECU", "Ecuador"},
  158.         {"EGY", "Egypt"},
  159.         {"ERI", "Eritrea"},
  160.         {"ESP", "Spain"},
  161.         {"EST", "Estonia"},
  162.         {"ETH", "Ethiopia"},
  163.         {"EU" , "Europe"},
  164.         {"FIN", "Finland"},
  165.         {"FJI", "Fiji"},
  166.         {"FRA", "France"},
  167.         {"FRO", "Faroe Islands"},
  168.         {"FSM", "Micronesia"},
  169.         {"GAB", "Gabon"},
  170.         {"GBR", "United Kingdom"},
  171.         {"GEO", "Georgia"},
  172.         {"GGY", "Guernsey"},
  173.         {"GHA", "Ghana"},
  174.         {"GIB", "Gibraltar"},
  175.         {"GIN", "Guinea"},
  176.         {"GLP", "Guadeloupe"},
  177.         {"GMB", "Gambia"},
  178.         {"GNB", "Guinea-Bissau"},
  179.         {"GNQ", "Equatorial Guinea"},
  180.         {"GRC", "Greece"},
  181.         {"GRD", "Grenada"},
  182.         {"GRL", "Greenland"},
  183.         {"GTM", "Guatemala"},
  184.         {"GUF", "French Guiana"},
  185.         {"GUM", "Guam"},
  186.         {"GUY", "Guyana"},
  187.         {"HKG", "Hong Kong"},
  188.         {"HND", "Honduras"},
  189.         {"HRV", "Croatia"},
  190.         {"HTI", "Haiti"},
  191.         {"HUN", "Hungary"},
  192.         {"IDN", "Indonesia"},
  193.         {"IMN", "Isle of Man"},
  194.         {"IND", "India"},
  195.         {"IOT", "Chagos Islands"},
  196.         {"IRL", "Ireland"},
  197.         {"IRN", "Iran"},
  198.         {"IRQ", "Iraq"},
  199.         {"ISL", "Iceland"},
  200.         {"ISR", "Israel"},
  201.         {"ITA", "Italy"},
  202.         {"JAM", "Jamaica"},
  203.         {"JEY", "Jersey"},
  204.         {"JOR", "Jordan"},
  205.         {"JPN", "Japan"},
  206.         {"KAZ", "Kazakhstan"},
  207.         {"KEN", "Kenya"},
  208.         {"KGZ", "Kyrgyzstan"},
  209.         {"KHM", "Cambodia"},
  210.         {"KIR", "Kiribati"},
  211.         {"KNA", "St. Kitts and Nevis"},
  212.         {"KOR", "South Korea"},
  213.         {"KWT", "Kuwait"},
  214.         {"LAN", "Local network"},
  215.         {"LAO", "Laos"},
  216.         {"LBN", "Lebanon"},
  217.         {"LBR", "Liberia"},
  218.         {"LBY", "Libya"},
  219.         {"LCA", "St. Lucia"},
  220.         {"LIE", "Liechtenstein"},
  221.         {"LKA", "Sri Lanka"},
  222.         {"LOC", "Localhost"},
  223.         {"LSO", "Lesotho"},
  224.         {"LTU", "Lithuania"},
  225.         {"LUX", "Luxembourg"},
  226.         {"LVA", "Latvia"},
  227.         {"MAC", "Macau"},
  228.         {"MAF", "St. Martin"},
  229.         {"MAR", "Morocco"},
  230.         {"MCO", "Monaco"},
  231.         {"MDA", "Moldova"},
  232.         {"MDG", "Madagascar"},
  233.         {"MDV", "Maldives"},
  234.         {"MEX", "Mexico"},
  235.         {"MHL", "Marshall Islands"},
  236.         {"MKD", "Macedonia"},
  237.         {"MLI", "Mali"},
  238.         {"MLT", "Malta"},
  239.         {"MMR", "Burma"},
  240.         {"MNE", "Montenegro"},
  241.         {"MNG", "Mongolia"},
  242.         {"MNP", "Northern Mariana Islands"},
  243.         {"MOZ", "Mozambique"},
  244.         {"MRT", "Mauritania"},
  245.         {"MSR", "Montserrat"},
  246.         {"MTQ", "Martinique"},
  247.         {"MUS", "Mauritius"},
  248.         {"MWI", "Malawi"},
  249.         {"MYS", "Malaysia"},
  250.         {"NAM", "Namibia"},
  251.         {"NCL", "New Caledonia"},
  252.         {"NER", "Niger"},
  253.         {"NFK", "Norfolk Island"},
  254.         {"NGA", "Nigeria"},
  255.         {"NIC", "Nicaragua"},
  256.         {"NIU", "Niue"},
  257.         {"NLD", "Netherlands"},
  258.         {"NOR", "Norway"},
  259.         {"NPL", "Nepal"},
  260.         {"NRU", "Nauru"},
  261.         {"NZL", "New Zealand"},
  262.         {"OMN", "Oman"},
  263.         {"PAK", "Pakistan"},
  264.         {"PAN", "Panama"},
  265.         {"PER", "Peru"},
  266.         {"PHL", "Philippines"},
  267.         {"PLW", "Palau"},
  268.         {"PNG", "Papua New Guinea"},
  269.         {"POL", "Poland"},
  270.         {"PRI", "Puerto Rico"},
  271.         {"PRK", "North Korea"},
  272.         {"PRT", "Portugal"},
  273.         {"PRY", "Paraguay"},
  274.         {"PSE", "Palestine"},
  275.         {"PYF", "French Polynesia"},
  276.         {"QAT", "Qatar"},
  277.         {"REU", "Reunion"},
  278.         {"ROM", "Romania"},
  279.         {"RUS", "Russia"},
  280.         {"RWA", "Rwanda"},
  281.         {"SAU", "Saudi Arabia"},
  282.         {"SDN", "Sudan"},
  283.         {"SEN", "Senegal"},
  284.         {"SGP", "Singapore"},
  285.         {"SLB", "Solomon Islands"},
  286.         {"SLE", "Sierra Leone"},
  287.         {"SLV", "El Salvador"},
  288.         {"SMR", "San Marino"},
  289.         {"SOM", "Somalia"},
  290.         {"SPM", "St. Pierre and Miquelon"},
  291.         {"SRB", "Serbia"},
  292.         {"SSD", "South Sudan"},
  293.         {"STP", "Sao Tome and Principe"},
  294.         {"SUR", "Suriname"},
  295.         {"SVK", "Slovakia"},
  296.         {"SVN", "Slovenia"},
  297.         {"SWE", "Sweden"},
  298.         {"SWZ", "Swaziland"},
  299.         {"SYC", "Seychelles"},
  300.         {"SYR", "Syria"},
  301.         {"TCA", "Turks and Caicos Islands"},
  302.         {"TCD", "Chad"},
  303.         {"TGO", "Togo"},
  304.         {"THA", "Thailand"},
  305.         {"TJK", "Tajikistan"},
  306.         {"TKL", "Tokelau"},
  307.         {"TKM", "Turkmenistan"},
  308.         {"TLS", "Timor-Leste"},
  309.         {"TON", "Tonga"},
  310.         {"TTO", "Trinidad and Tobago"},
  311.         {"TUN", "Tunisia"},
  312.         {"TUR", "Turkey"},
  313.         {"TUV", "Tuvalu"},
  314.         {"TWN", "Taiwan"},
  315.         {"TZA", "Tanzania"},
  316.         {"UGA", "Uganda"},
  317.         {"UKR", "Ukraine"},
  318.         {"URY", "Uruguay"},
  319.         {"USA", "United States"},
  320.         {"UZB", "Uzbekistan"},
  321.         {"VAT", "Vatican City"},
  322.         {"VCT", "St. Vincent and Grenadines"},
  323.         {"VEN", "Venezuela"},
  324.         {"VGB", "Virgin Islands (UK)"},
  325.         {"VIR", "Virgin Islands (US)"},
  326.         {"VNM", "Vietnam"},
  327.         {"VUT", "Vanuatu"},
  328.         {"WLF", "Wallis and Futuna"},
  329.         {"WSM", "Samoa"},
  330.         {"YEM", "Yemen"},
  331.         {"ZAF", "South Africa"},
  332.         {"ZMB", "Zambia"},
  333.         {"ZWE", "Zimbabwe"},
  334.         {"ZZZ", "Reserved"},
  335.     };
  336.    
  337.     // =========================================================================
  338.     // Find a country definition by code
  339.     int FindCountry (char* code) {
  340.         for (unsigned int i = 0; i < sizeof (CountryData) / sizeof (Country_t); i++)
  341.             if (!strcmp (CountryData[i].code, code))
  342.                 return i;
  343.         return -1;
  344.     }
  345.    
  346.     // =========================================================================
  347.     // Parses the CSV database and builds the IP database.
  348.     bool LoadIPTable (const char* path) {
  349.         FILE* fp = fopen (path, "r");
  350.         if (!fp) {
  351.             ErrorMsg = "Could not open IP table for reading!";
  352.             return false;
  353.         }
  354.        
  355.         ULONG x = 0;
  356.         char line[256];
  357.        
  358.         // First, skim through the file to count the amount of entries;
  359.         entryCount = 0;
  360.         while (fgets (line, 256, fp)) {
  361.             if (line[0] == '#' || line[0] == '\n')
  362.                 continue;
  363.             entryCount++;
  364.         }
  365.        
  366.         // Rewind back to start of file
  367.         fseek (fp, 0, SEEK_SET);
  368.        
  369.         // Allocate the table
  370.         IPLinks = new link_t[entryCount];
  371.        
  372.         unsigned def = 0;
  373.         while (fgets (line, 256, fp)) {
  374.             // Ignore comments
  375.             if (line[0] == '#' || line[0] == '\n')
  376.                 continue;
  377.            
  378.             // This shouldn't be happening but I'm still paranoid
  379.             if (x >= entryCount) {
  380.                 Printf ("\\cKIP2C: Warning: Could not fit the entire IP2C database to memory!\n");
  381.                 break;
  382.             }
  383.            
  384.             int i = 1;
  385.             IPLinks[x].minIP = atoi (line + i);
  386.            
  387.             // Skip past unneeded junk
  388.             for (int j = 0; j < 5; j++) {
  389.                 do
  390.                     i++;
  391.                 while (*(line + i) != '"');
  392.                 i += 3;
  393.             }
  394.            
  395.             // Read the country code
  396.             char countrycode[4];
  397.             strncpy (countrycode, line + i, 3);
  398.            
  399.             // Add the null terminator, assuming there's no one-character
  400.             // country codes.
  401.             if (countrycode[2] == '"') {
  402.                 // 2-character code
  403.                 countrycode[2] = '\0';
  404.                 i += 5;
  405.             } else {
  406.                 // 3-character code
  407.                 countrycode[3] = '\0';
  408.                 i += 6;
  409.             }
  410.            
  411.             // Find the country for this code
  412.             int ci = FindCountry (countrycode);
  413.            
  414.             if (ci == -1) {
  415.                 Printf ("IP2C: Couldn't find country definition for `%s`!\n", countrycode);
  416.                 IPLinks[x].country = NULL;
  417.             } else {
  418.                 IPLinks[x].country = &CountryData[ci];
  419.             }
  420.             x++;
  421.         }
  422.        
  423.         // Mark a NULL entry to sign the end of list.
  424.         IPLinks[x].country = NULL;
  425.         return true;
  426.     }
  427.    
  428.     // =========================================================================
  429.     // Gets the country data of a given IP.
  430.     const Country_t* GetCountry (ULONG ip) {
  431.         if (!IP2CReady)
  432.             return NULL;
  433.        
  434.         // Localhost
  435.         if (ip == 0x7F000001)
  436.             return Localhost;
  437.        
  438.         // Local network
  439.         if (ip >= 0xC0A80000 && ip <= 0xC0A8FFFF)
  440.             return LocalNetwork;
  441.        
  442.         link_t* IPLink = NULL;
  443.         for (int i = 0; i < MAX_ENTRIES; i++) {
  444.             if (!IPLinks[i].country)
  445.                 break;
  446.            
  447.             if (ip > IPLinks[i].minIP)
  448.                 continue;
  449.            
  450.             return IPLinks[i - 1].country;
  451.         }
  452.        
  453.         return NULL;
  454.     }
  455.    
  456.     // =========================================================================
  457.     // Variant that can handle the Zandronum IP type.
  458.     const Country_t* GetCountry (NETADDRESS_s ip) {
  459.         ULONG ulIP = (ip.abIP[0] * 0x1000000) + (ip.abIP[1] * 0x10000) + (ip.abIP[2] * 0x100) + ip.abIP[3];
  460.         return GetCountry (ulIP);
  461.     }
  462.    
  463.     // =========================================================================
  464.     // Get a country by index
  465.     const Country_t* GetCountryByIndex (int id) {
  466.         if (id < 0 || id >= (int)(sizeof (CountryData) / sizeof (CountryData[0])))
  467.             return NULL;
  468.         return &CountryData[id];
  469.     }
  470.    
  471.     const Country_t* GetCountryByName (char* countryName) {
  472.         for (int i = 0; i < (int)(sizeof (CountryData) / sizeof (CountryData[0])); i++)
  473.             if (!strcmp (CountryData[i].name, countryName))
  474.                 return &CountryData[i];
  475.        
  476.         return NULL;
  477.     }
  478.    
  479.     const Country_t* GetCountryByCode (char* countryCode) {
  480.         for (int i = 0; i < (int)(sizeof (CountryData) / sizeof (CountryData[0])); i++)
  481.             if (!strcmp (CountryData[i].code, countryCode))
  482.                 return &CountryData[i];
  483.        
  484.         return NULL;
  485.     }
  486.    
  487.     // =========================================================================
  488.     // Get an index by country
  489.     long GetCountryIndex (const Country_t* country) {
  490.         if (!country)
  491.             return -1;
  492.        
  493.         return country - CountryData;
  494.     }
  495.    
  496.     // =========================================================================
  497.     // Does the necessary procedures to ready the IP2C database.
  498.     void Initiate () {
  499.         // Only the server needs the IP2C database.
  500.         if (NETWORK_GetState() != NETSTATE_SERVER || !sv_ip2c)
  501.             return;
  502.        
  503.         // If there ever are more than 255 countries, the networking needs to be
  504.         // updated to send a short for the country data. This is an alarm for that.
  505.         assert (sizeof (CountryData) / sizeof (CountryData[0]) <= 255);
  506.        
  507.         // load the actual database.
  508.         LoadDB ();
  509.        
  510.         // Locate the LAN and localhost entries in the country table.
  511.         for (unsigned int i = 0; i < sizeof (CountryData) / sizeof (CountryData[0]); i++) {
  512.             if (!strcmp (CountryData[i].code, "LAN"))
  513.                 LocalNetwork = &CountryData[i];
  514.             else if (!strcmp (CountryData[i].code, "LOC"))
  515.                 Localhost = &CountryData[i];
  516.         }
  517.        
  518.         atterm (IP2C::Destroy);
  519.     }
  520.    
  521.     void UnloadDB () {
  522.         if (!IP2CReady)
  523.             return;
  524.        
  525.         delete[] IPLinks;
  526.         IP2CReady = false;
  527.         IPLinks = NULL;
  528.        
  529.         Printf ("IP2C: IP-to-country database unloaded.\n");
  530.     }
  531.    
  532.     void LoadDB () {
  533.         if (IP2CReady)
  534.             return;
  535.        
  536.         if (!LoadIPTable (sv_ip2c_dbfile)) {
  537.             Printf ("IP2C: Failed to load the IP2C database!\n");
  538.             return;
  539.         }
  540.        
  541.         Printf ("IP2C: IP-to-country database loaded.\n");
  542.         IP2CReady = true;
  543.     }
  544.    
  545.     void Destroy () {
  546.         delete[] IPLinks;
  547.     }
  548.    
  549.     // =========================================================================
  550.     // Access function for IP2CReady
  551.     bool IsReady () {
  552.         return IP2CReady;
  553.     }
  554. }
Advertisement
Add Comment
Please, Sign In to add comment