mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
1258 lines
60 KiB
C
1258 lines
60 KiB
C
/*H*************************************************************************************************
|
|
|
|
\File netconnwin.c
|
|
|
|
\Description
|
|
Provides network setup and teardown support. Does not actually create any
|
|
kind of network connections (see NetPlay).
|
|
|
|
\Copyright
|
|
Copyright (c) 2001-2010 Electronic Arts Inc.
|
|
|
|
\Version 03/12/2001 (gschaefer) First version
|
|
\Version 12/16/2001 (sbevan) Edited config file hack in NetConnDevStart
|
|
\Version 06/23/2009 (mclouatre) _NetConFindAdapter() changed to _NetConnFindMacAddress()
|
|
|
|
*************************************************************************************************H*/
|
|
|
|
/*** Include files ********************************************************************************/
|
|
|
|
#define WIN32_LEAN_AND_MEAN 1 // avoid extra stuff
|
|
|
|
#pragma warning(push,0)
|
|
#include <windows.h>
|
|
#pragma warning(pop)
|
|
|
|
#include <winsock2.h>
|
|
#include <iphlpapi.h> // for GetAdaptersAddresses()
|
|
#include <iptypes.h> // for PIP_ADAPTER_ADDRESSES
|
|
#include <stdlib.h> // for strtol()
|
|
|
|
#include "DirtySDK/dirtysock.h"
|
|
#include "DirtySDK/dirtyvers.h"
|
|
#include "DirtySDK/dirtysock/dirtymem.h"
|
|
#include "DirtySDK/dirtysock/dirtycert.h"
|
|
#include "DirtySDK/dirtylang.h" // for locality macros and definitions
|
|
#include "DirtySDK/dirtysock/netconn.h"
|
|
#include "DirtySDK/proto/protossl.h"
|
|
#include "DirtySDK/proto/protoupnp.h"
|
|
#include "netconncommon.h"
|
|
|
|
/*** Defines **************************************************************************************/
|
|
|
|
// LOCALE_SNAME: defined in WinNls.h (WINVER >= 0x0600). This block is just there for the case where the define is absent.
|
|
#ifndef LOCALE_SNAME
|
|
#define LOCALE_SNAME 0x0000005c // locale name (ie: en-us)
|
|
#endif
|
|
|
|
//! GetGeoInfo returns XX for unknown country
|
|
#define NETCONNWIN_COUNTRY_UNKNOWN_STR ("XX")
|
|
|
|
//! UPNP port
|
|
#define NETCONN_DEFAULT_UPNP_PORT (3659)
|
|
|
|
/*** Macros ***************************************************************************************/
|
|
|
|
/*** Type Definitions *****************************************************************************/
|
|
|
|
//! private module state
|
|
typedef struct NetConnRefT
|
|
{
|
|
NetConnCommonRefT Common; //!< cross-platform netconn data (must come first!)
|
|
|
|
enum
|
|
{
|
|
ST_INIT,
|
|
ST_CONN,
|
|
ST_IDLE,
|
|
} eState;
|
|
|
|
int32_t iPeerPort; //!< peer port to be opened by upnp; if zero, still find upnp router but don't open a port
|
|
ProtoUpnpRefT *pProtoUpnp; //!< protoupnp module state
|
|
int32_t iThreadCpuAffinity; //!< cpu affinity we use for our internal threads
|
|
} NetConnRefT;
|
|
|
|
/*** Function Prototypes **************************************************************************/
|
|
|
|
/*** Variables ************************************************************************************/
|
|
|
|
//! mapping table to map Windows Language IDs to DirtySock encodings
|
|
/*
|
|
Language Identifier Constants and Strings: http://msdn.microsoft.com/en-us/library/dd318693(v=vs.85).aspx
|
|
|
|
1. In order to reduce the size of the mapping table:
|
|
if locality(Primary Id, SUBLANG_NEUTRAL) == locality(Primary Id, SUBLANG_DEFAULT),
|
|
then only locality(Primary Id, SUBLANG_DEFAULT) is included by the table.
|
|
That means if we can't find locality(Primary Id, SUBLANG_NEUTRAL) in the table,
|
|
we should search the table again with langid(Primary Id, SUBLANG_DEFAULT).
|
|
Defined in WinNT.h:
|
|
#define SUBLANG_NEUTRAL 0x00 // language neutral
|
|
#define SUBLANG_DEFAULT 0x01 // user default
|
|
#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 // Arabic (Saudi Arabia)
|
|
// normally, specific sublangs (ex. SUBLANG_ARABIC_SAUDI_ARABIA) are used by the table instead of using SUBLANG_DEFAULT.
|
|
|
|
Another reason why we don't define all locality(Primary Id, SUBLANG_NEUTRAL) is:
|
|
Normally Windows API returns langid(Primary Id, specific_sublang) instead of langid(Primary Id, SUBLANG_NEUTRAL).
|
|
|
|
2. The reason why we use a mapping table is because Windows API GetLocaleInfo(LOCALE_SNAME) is only available under Vista (or later).
|
|
|
|
3. The result of GetLocaleInfo(LOCALE_SNAME) will be used to verify if the mapping table is good by _NetConnVerifyAllLocales.
|
|
(debug version only, Vista / Windows7 only)
|
|
|
|
4. NetConnStatus('locl', 0, NULL, 0) can be used to obtain locality for local system.
|
|
The return value of NetConnStatus('locl', 0, NULL, 0) is similar to the return value of "locl" on the XBOX 360, ex. 'enUS'.
|
|
*/
|
|
static uint16_t _NetConn_WindowsLocaleMap[214][3] =
|
|
{
|
|
{ MAKELANGID(LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA), LOBBYAPI_LANGUAGE_AFRIKAANS, LOBBYAPI_COUNTRY_SOUTH_AFRICA },
|
|
{ MAKELANGID(LANG_ALBANIAN, SUBLANG_ALBANIAN_ALBANIA), LOBBYAPI_LANGUAGE_ALBANIAN, LOBBYAPI_COUNTRY_ALBANIA },
|
|
{ MAKELANGID(LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA), LOBBYAPI_LANGUAGE_AMHARIC, LOBBYAPI_COUNTRY_ETHIOPIA },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_ALGERIA), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_ALGERIA },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_BAHRAIN },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_EGYPT), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_EGYPT },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_IRAQ), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_IRAQ },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_JORDAN), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_JORDAN },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_KUWAIT), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_KUWAIT },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_LEBANON), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_LEBANON },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_LIBYA), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_LIBYAN_ARAB_JAMAHIRIYA },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_MOROCCO), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_MOROCCO },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_OMAN), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_OMAN },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_QATAR },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_SAUDI_ARABIA },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SYRIA), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_SYRIAN_ARAB_REPUBLIC },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_TUNISIA), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_TUNISIA },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_UAE), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_UNITED_ARAB_EMIRATES },
|
|
{ MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_YEMEN), LOBBYAPI_LANGUAGE_ARABIC, LOBBYAPI_COUNTRY_YEMEN },
|
|
{ MAKELANGID(LANG_ARMENIAN, SUBLANG_ARMENIAN_ARMENIA), LOBBYAPI_LANGUAGE_ARMENIAN, LOBBYAPI_COUNTRY_ARMENIA },
|
|
{ MAKELANGID(LANG_ASSAMESE, SUBLANG_ASSAMESE_INDIA), LOBBYAPI_LANGUAGE_ASSAMESE, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_AZERI, SUBLANG_AZERI_CYRILLIC), LOBBYAPI_LANGUAGE_AZERBAIJANI, LOBBYAPI_COUNTRY_AZERBAIJAN },
|
|
{ MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), LOBBYAPI_LANGUAGE_AZERBAIJANI, LOBBYAPI_COUNTRY_AZERBAIJAN },
|
|
{ MAKELANGID(LANG_BASHKIR, SUBLANG_BASHKIR_RUSSIA), LOBBYAPI_LANGUAGE_BASHKIR, LOBBYAPI_COUNTRY_RUSSIAN_FEDERATION },
|
|
{ MAKELANGID(LANG_BASQUE, SUBLANG_BASQUE_BASQUE), LOBBYAPI_LANGUAGE_BASQUE, LOBBYAPI_COUNTRY_SPAIN },
|
|
{ MAKELANGID(LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS), LOBBYAPI_LANGUAGE_BYELORUSSIAN, LOBBYAPI_COUNTRY_BELARUS },
|
|
{ MAKELANGID(LANG_BENGALI, SUBLANG_BENGALI_BANGLADESH), LOBBYAPI_LANGUAGE_BENGALI, LOBBYAPI_COUNTRY_BANGLADESH },
|
|
{ MAKELANGID(LANG_BENGALI, SUBLANG_BENGALI_INDIA), LOBBYAPI_LANGUAGE_BENGALI, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC), LOBBYAPI_LANGUAGE_BOSNIAN, LOBBYAPI_COUNTRY_BOSNIA_HERZEGOVINA },
|
|
{ MAKELANGID(LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN), LOBBYAPI_LANGUAGE_BOSNIAN, LOBBYAPI_COUNTRY_BOSNIA_HERZEGOVINA },
|
|
{ MAKELANGID(LANG_BRETON, SUBLANG_BRETON_FRANCE), LOBBYAPI_LANGUAGE_BRETON, LOBBYAPI_COUNTRY_FRANCE },
|
|
{ MAKELANGID(LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA), LOBBYAPI_LANGUAGE_BULGARIAN, LOBBYAPI_COUNTRY_BULGARIA },
|
|
{ MAKELANGID(LANG_CATALAN, SUBLANG_CATALAN_CATALAN), LOBBYAPI_LANGUAGE_CATALAN, LOBBYAPI_COUNTRY_SPAIN },
|
|
{ MAKELANGID(LANG_CHINESE, SUBLANG_NEUTRAL), LOBBYAPI_LANGUAGE_CHINESE, LOBBYAPI_COUNTRY_CHINA },
|
|
{ MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), LOBBYAPI_LANGUAGE_CHINESE, LOBBYAPI_COUNTRY_HONG_KONG },
|
|
{ MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_MACAU), LOBBYAPI_LANGUAGE_CHINESE, LOBBYAPI_COUNTRY_MACAU },
|
|
{ MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE), LOBBYAPI_LANGUAGE_CHINESE, LOBBYAPI_COUNTRY_SINGAPORE },
|
|
{ MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), LOBBYAPI_LANGUAGE_CHINESE, LOBBYAPI_COUNTRY_CHINA },
|
|
{ MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL), LOBBYAPI_LANGUAGE_CHINESE, LOBBYAPI_COUNTRY_TAIWAN },
|
|
{ MAKELANGID(LANG_CORSICAN, SUBLANG_CORSICAN_FRANCE), LOBBYAPI_LANGUAGE_CORSICAN, LOBBYAPI_COUNTRY_FRANCE },
|
|
{ MAKELANGID(LANG_CROATIAN, SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN), LOBBYAPI_LANGUAGE_CROATIAN, LOBBYAPI_COUNTRY_BOSNIA_HERZEGOVINA },
|
|
{ MAKELANGID(LANG_CROATIAN, SUBLANG_CROATIAN_CROATIA), LOBBYAPI_LANGUAGE_CROATIAN, LOBBYAPI_COUNTRY_CROATIA },
|
|
{ MAKELANGID(LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC), LOBBYAPI_LANGUAGE_CZECH, LOBBYAPI_COUNTRY_CZECH_REPUBLIC },
|
|
{ MAKELANGID(LANG_DANISH, SUBLANG_DANISH_DENMARK), LOBBYAPI_LANGUAGE_DANISH, LOBBYAPI_COUNTRY_DENMARK },
|
|
{ MAKELANGID(LANG_DIVEHI, SUBLANG_DIVEHI_MALDIVES), LOBBYAPI_LANGUAGE_DIVEHI, LOBBYAPI_COUNTRY_MALDIVES },
|
|
{ MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), LOBBYAPI_LANGUAGE_DUTCH, LOBBYAPI_COUNTRY_BELGIUM },
|
|
{ MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), LOBBYAPI_LANGUAGE_DUTCH, LOBBYAPI_COUNTRY_NETHERLANDS },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_AUSTRALIA },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_BELIZE },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_CANADA },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CARIBBEAN), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_UNKNOWN },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_INDIA), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_EIRE), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_IRELAND },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_JAMAICA), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_JAMAICA },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_MALAYSIA), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_MALAYSIA },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_NZ), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_NEW_ZEALAND },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_PHILIPPINES },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_SINGAPORE), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_SINGAPORE },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_SOUTH_AFRICA },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_TRINIDAD), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_TRINIDAD_AND_TOBAGO },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_UNITED_KINGDOM },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_UNITED_STATES },
|
|
{ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE), LOBBYAPI_LANGUAGE_ENGLISH, LOBBYAPI_COUNTRY_ZIMBABWE },
|
|
{ MAKELANGID(LANG_ESTONIAN, SUBLANG_ESTONIAN_ESTONIA), LOBBYAPI_LANGUAGE_ESTONIAN, LOBBYAPI_COUNTRY_ESTONIA },
|
|
{ MAKELANGID(LANG_FAEROESE, SUBLANG_FAEROESE_FAROE_ISLANDS), LOBBYAPI_LANGUAGE_FAEROESE, LOBBYAPI_COUNTRY_FAEROE_ISLANDS },
|
|
{ MAKELANGID(LANG_FINNISH, SUBLANG_FINNISH_FINLAND), LOBBYAPI_LANGUAGE_FINNISH, LOBBYAPI_COUNTRY_FINLAND },
|
|
{ MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN), LOBBYAPI_LANGUAGE_FRENCH, LOBBYAPI_COUNTRY_BELGIUM },
|
|
{ MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_CANADIAN), LOBBYAPI_LANGUAGE_FRENCH, LOBBYAPI_COUNTRY_CANADA },
|
|
{ MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH), LOBBYAPI_LANGUAGE_FRENCH, LOBBYAPI_COUNTRY_FRANCE },
|
|
{ MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG), LOBBYAPI_LANGUAGE_FRENCH, LOBBYAPI_COUNTRY_LUXEMBOURG },
|
|
{ MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_MONACO), LOBBYAPI_LANGUAGE_FRENCH, LOBBYAPI_COUNTRY_MONACO },
|
|
{ MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_SWISS), LOBBYAPI_LANGUAGE_FRENCH, LOBBYAPI_COUNTRY_SWITZERLAND },
|
|
{ MAKELANGID(LANG_FRISIAN, SUBLANG_FRISIAN_NETHERLANDS), LOBBYAPI_LANGUAGE_FRISIAN, LOBBYAPI_COUNTRY_NETHERLANDS },
|
|
{ MAKELANGID(LANG_GALICIAN, SUBLANG_GALICIAN_GALICIAN), LOBBYAPI_LANGUAGE_GALICIAN, LOBBYAPI_COUNTRY_SPAIN },
|
|
{ MAKELANGID(LANG_GEORGIAN, SUBLANG_GEORGIAN_GEORGIA), LOBBYAPI_LANGUAGE_GEORGIAN, LOBBYAPI_COUNTRY_GEORGIA },
|
|
{ MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), LOBBYAPI_LANGUAGE_GERMAN, LOBBYAPI_COUNTRY_AUSTRIA },
|
|
{ MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), LOBBYAPI_LANGUAGE_GERMAN, LOBBYAPI_COUNTRY_GERMANY },
|
|
{ MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_LIECHTENSTEIN), LOBBYAPI_LANGUAGE_GERMAN, LOBBYAPI_COUNTRY_LIECHTENSTEIN },
|
|
{ MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG), LOBBYAPI_LANGUAGE_GERMAN, LOBBYAPI_COUNTRY_LUXEMBOURG },
|
|
{ MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), LOBBYAPI_LANGUAGE_GERMAN, LOBBYAPI_COUNTRY_SWITZERLAND },
|
|
{ MAKELANGID(LANG_GREEK, SUBLANG_GREEK_GREECE), LOBBYAPI_LANGUAGE_GREEK, LOBBYAPI_COUNTRY_GREECE },
|
|
{ MAKELANGID(LANG_GREENLANDIC, SUBLANG_GREENLANDIC_GREENLAND), LOBBYAPI_LANGUAGE_GREENLANDIC, LOBBYAPI_COUNTRY_GREENLAND },
|
|
{ MAKELANGID(LANG_GUJARATI, SUBLANG_GUJARATI_INDIA), LOBBYAPI_LANGUAGE_GUJARATI, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_HAUSA, SUBLANG_HAUSA_NIGERIA_LATIN), LOBBYAPI_LANGUAGE_HAUSA, LOBBYAPI_COUNTRY_NIGERIA },
|
|
{ MAKELANGID(LANG_HEBREW, SUBLANG_HEBREW_ISRAEL), LOBBYAPI_LANGUAGE_HEBREW, LOBBYAPI_COUNTRY_ISRAEL },
|
|
{ MAKELANGID(LANG_HINDI, SUBLANG_HINDI_INDIA), LOBBYAPI_LANGUAGE_HINDI, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY), LOBBYAPI_LANGUAGE_HUNGARIAN, LOBBYAPI_COUNTRY_HUNGARY },
|
|
{ MAKELANGID(LANG_ICELANDIC, SUBLANG_ICELANDIC_ICELAND), LOBBYAPI_LANGUAGE_ICELANDIC, LOBBYAPI_COUNTRY_ICELAND },
|
|
{ MAKELANGID(LANG_IGBO, SUBLANG_IGBO_NIGERIA), LOBBYAPI_LANGUAGE_IGBO, LOBBYAPI_COUNTRY_NIGERIA },
|
|
{ MAKELANGID(LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA), LOBBYAPI_LANGUAGE_INDONESIAN, LOBBYAPI_COUNTRY_INDONESIA },
|
|
{ MAKELANGID(LANG_INUKTITUT, SUBLANG_INUKTITUT_CANADA_LATIN), LOBBYAPI_LANGUAGE_INUKTITUT, LOBBYAPI_COUNTRY_CANADA },
|
|
{ MAKELANGID(LANG_INUKTITUT, SUBLANG_INUKTITUT_CANADA), LOBBYAPI_LANGUAGE_INUKTITUT, LOBBYAPI_COUNTRY_CANADA },
|
|
{ MAKELANGID(LANG_IRISH, SUBLANG_NEUTRAL), LOBBYAPI_LANGUAGE_IRISH, LOBBYAPI_COUNTRY_IRELAND },
|
|
{ MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), LOBBYAPI_LANGUAGE_IRISH, LOBBYAPI_COUNTRY_IRELAND },
|
|
{ MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), LOBBYAPI_LANGUAGE_ITALIAN, LOBBYAPI_COUNTRY_ITALY },
|
|
{ MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN_SWISS), LOBBYAPI_LANGUAGE_ITALIAN, LOBBYAPI_COUNTRY_SWITZERLAND },
|
|
{ MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), LOBBYAPI_LANGUAGE_JAPANESE, LOBBYAPI_COUNTRY_JAPAN },
|
|
{ MAKELANGID(LANG_KANNADA, SUBLANG_KANNADA_INDIA), LOBBYAPI_LANGUAGE_KANNADA, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_KAZAK, SUBLANG_KAZAK_KAZAKHSTAN), LOBBYAPI_LANGUAGE_KAZAKH, LOBBYAPI_COUNTRY_KAZAKHSTAN },
|
|
{ MAKELANGID(LANG_KHMER, SUBLANG_KHMER_CAMBODIA), LOBBYAPI_LANGUAGE_CAMBODIAN, LOBBYAPI_COUNTRY_CAMBODIA },
|
|
{ MAKELANGID(LANG_KINYARWANDA, SUBLANG_KINYARWANDA_RWANDA), LOBBYAPI_LANGUAGE_KINYARWANDA, LOBBYAPI_COUNTRY_RWANDA },
|
|
{ MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN), LOBBYAPI_LANGUAGE_KOREAN, LOBBYAPI_COUNTRY_KOREA_REPUBLIC_OF },
|
|
{ MAKELANGID(LANG_KYRGYZ, SUBLANG_KYRGYZ_KYRGYZSTAN), LOBBYAPI_LANGUAGE_KIRGHIZ, LOBBYAPI_COUNTRY_KYRGYZSTAN },
|
|
{ MAKELANGID(LANG_LAO, SUBLANG_LAO_LAO), LOBBYAPI_LANGUAGE_LAOTHIAN, LOBBYAPI_COUNTRY_LAO_PEOPLES_DEMOCRATIC_REPUBLIC },
|
|
{ MAKELANGID(LANG_LATVIAN, SUBLANG_LATVIAN_LATVIA), LOBBYAPI_LANGUAGE_LATVIAN_LETTISH, LOBBYAPI_COUNTRY_LATVIA },
|
|
{ MAKELANGID(LANG_LITHUANIAN, SUBLANG_LITHUANIAN), LOBBYAPI_LANGUAGE_LITHUANIAN, LOBBYAPI_COUNTRY_LITHUANIA },
|
|
{ MAKELANGID(LANG_LUXEMBOURGISH, SUBLANG_LUXEMBOURGISH_LUXEMBOURG), LOBBYAPI_LANGUAGE_LUXEMBOURGISH, LOBBYAPI_COUNTRY_LUXEMBOURG },
|
|
{ MAKELANGID(LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA), LOBBYAPI_LANGUAGE_MACEDONIAN, LOBBYAPI_COUNTRY_MACEDONIA_THE_FORMER_YUGOSLAV_REPUBLIC_OF },
|
|
{ MAKELANGID(LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM), LOBBYAPI_LANGUAGE_MALAY, LOBBYAPI_COUNTRY_BRUNEI_DARUSSALAM },
|
|
{ MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), LOBBYAPI_LANGUAGE_MALAY, LOBBYAPI_COUNTRY_MALAYSIA },
|
|
{ MAKELANGID(LANG_MALAYALAM, SUBLANG_MALAYALAM_INDIA), LOBBYAPI_LANGUAGE_MALAYALAM, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_MALTESE, SUBLANG_MALTESE_MALTA), LOBBYAPI_LANGUAGE_MALTESE, LOBBYAPI_COUNTRY_MALTA },
|
|
{ MAKELANGID(LANG_MAORI, SUBLANG_MAORI_NEW_ZEALAND), LOBBYAPI_LANGUAGE_MAORI, LOBBYAPI_COUNTRY_NEW_ZEALAND },
|
|
{ MAKELANGID(LANG_MARATHI, SUBLANG_MARATHI_INDIA), LOBBYAPI_LANGUAGE_MARATHI, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), LOBBYAPI_LANGUAGE_MONGOLIAN, LOBBYAPI_COUNTRY_MONGOLIA },
|
|
{ MAKELANGID(LANG_MONGOLIAN, SUBLANG_MONGOLIAN_PRC), LOBBYAPI_LANGUAGE_MONGOLIAN, LOBBYAPI_COUNTRY_CHINA },
|
|
{ MAKELANGID(LANG_NEPALI, SUBLANG_NEPALI_NEPAL), LOBBYAPI_LANGUAGE_NEPALI, LOBBYAPI_COUNTRY_NEPAL },
|
|
{ MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL), LOBBYAPI_LANGUAGE_NORWEGIAN_BOKMAL, LOBBYAPI_COUNTRY_NORWAY },
|
|
{ MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK), LOBBYAPI_LANGUAGE_NORWEGIAN_NYNORSK, LOBBYAPI_COUNTRY_NORWAY },
|
|
{ MAKELANGID(LANG_OCCITAN, SUBLANG_OCCITAN_FRANCE), LOBBYAPI_LANGUAGE_OCCITAN, LOBBYAPI_COUNTRY_FRANCE },
|
|
{ MAKELANGID(LANG_ORIYA, SUBLANG_ORIYA_INDIA), LOBBYAPI_LANGUAGE_ORIYA, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_PASHTO, SUBLANG_PASHTO_AFGHANISTAN), LOBBYAPI_LANGUAGE_PASHTO_PUSHTO, LOBBYAPI_COUNTRY_AFGHANISTAN },
|
|
{ MAKELANGID(LANG_PERSIAN, SUBLANG_PERSIAN_IRAN), LOBBYAPI_LANGUAGE_PERSIAN, LOBBYAPI_COUNTRY_IRAN },
|
|
{ MAKELANGID(LANG_POLISH, SUBLANG_POLISH_POLAND), LOBBYAPI_LANGUAGE_POLISH, LOBBYAPI_COUNTRY_POLAND },
|
|
{ MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), LOBBYAPI_LANGUAGE_PORTUGUESE, LOBBYAPI_COUNTRY_BRAZIL },
|
|
{ MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE), LOBBYAPI_LANGUAGE_PORTUGUESE, LOBBYAPI_COUNTRY_PORTUGAL },
|
|
{ MAKELANGID(LANG_PUNJABI, SUBLANG_PUNJABI_INDIA), LOBBYAPI_LANGUAGE_PUNJABI, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_QUECHUA, SUBLANG_QUECHUA_BOLIVIA), LOBBYAPI_LANGUAGE_QUECHUA, LOBBYAPI_COUNTRY_BOLIVIA },
|
|
{ MAKELANGID(LANG_QUECHUA, SUBLANG_QUECHUA_ECUADOR), LOBBYAPI_LANGUAGE_QUECHUA, LOBBYAPI_COUNTRY_ECUADOR },
|
|
{ MAKELANGID(LANG_QUECHUA, SUBLANG_QUECHUA_PERU), LOBBYAPI_LANGUAGE_QUECHUA, LOBBYAPI_COUNTRY_PERU },
|
|
{ MAKELANGID(LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA), LOBBYAPI_LANGUAGE_ROMANIAN, LOBBYAPI_COUNTRY_ROMANIA },
|
|
{ MAKELANGID(LANG_ROMANSH, SUBLANG_ROMANSH_SWITZERLAND), LOBBYAPI_LANGUAGE_RHAETO_ROMANCE, LOBBYAPI_COUNTRY_SWITZERLAND },
|
|
{ MAKELANGID(LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA), LOBBYAPI_LANGUAGE_RUSSIAN, LOBBYAPI_COUNTRY_RUSSIAN_FEDERATION },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_NORTHERN_FINLAND), LOBBYAPI_LANGUAGE_SAMI, LOBBYAPI_COUNTRY_FINLAND },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_NORTHERN_NORWAY), LOBBYAPI_LANGUAGE_SAMI, LOBBYAPI_COUNTRY_NORWAY },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_NORTHERN_SWEDEN), LOBBYAPI_LANGUAGE_SAMI, LOBBYAPI_COUNTRY_SWEDEN },
|
|
{ MAKELANGID(LANG_SANSKRIT, SUBLANG_SANSKRIT_INDIA), LOBBYAPI_LANGUAGE_SANSKRIT, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC), LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_BOSNIA_HERZEGOVINA },
|
|
{ MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN),LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_BOSNIA_HERZEGOVINA },
|
|
{ MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC), LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_SERBIA_AND_MONTENEGRO },
|
|
{ MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_LATIN), LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_SERBIA_AND_MONTENEGRO },
|
|
{ MAKELANGID(LANG_SERBIAN, 0x0C), LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_MONTENEGRO },
|
|
{ MAKELANGID(LANG_SERBIAN, 0x0B), LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_MONTENEGRO },
|
|
{ MAKELANGID(LANG_SERBIAN, 0x0A), LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_SERBIA },
|
|
{ MAKELANGID(LANG_SERBIAN, 0x09), LOBBYAPI_LANGUAGE_SERBIAN, LOBBYAPI_COUNTRY_SERBIA },
|
|
{ MAKELANGID(LANG_SINHALESE, SUBLANG_SINHALESE_SRI_LANKA), LOBBYAPI_LANGUAGE_SINGHALESE, LOBBYAPI_COUNTRY_SRI_LANKA },
|
|
{ MAKELANGID(LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA), LOBBYAPI_LANGUAGE_SLOVAK, LOBBYAPI_COUNTRY_SLOVAKIA },
|
|
{ MAKELANGID(LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA), LOBBYAPI_LANGUAGE_SLOVENIAN, LOBBYAPI_COUNTRY_SLOVENIA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_ARGENTINA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_BOLIVIA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_CHILE), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_CHILE },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_COLOMBIA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_COSTA_RICA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_DOMINICAN_REPUBLIC), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_DOMINICAN_REPUBLIC },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_ECUADOR), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_ECUADOR },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_EL_SALVADOR },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_GUATEMALA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_HONDURAS), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_HONDURAS },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MEXICAN), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_MEXICO },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_NICARAGUA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_PANAMA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_PANAMA },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_PARAGUAY },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_PERU), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_PERU },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_PUERTO_RICO), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_PUERTO_RICO },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_SPAIN },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_SPAIN },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_US), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_UNITED_STATES },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_URUGUAY), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_URUGUAY },
|
|
{ MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA), LOBBYAPI_LANGUAGE_SPANISH, LOBBYAPI_COUNTRY_VENEZUELA },
|
|
{ MAKELANGID(LANG_SWAHILI, SUBLANG_DEFAULT), LOBBYAPI_LANGUAGE_SWAHILI, LOBBYAPI_COUNTRY_KENYA },
|
|
{ MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH_FINLAND), LOBBYAPI_LANGUAGE_SWEDISH, LOBBYAPI_COUNTRY_FINLAND },
|
|
{ MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), LOBBYAPI_LANGUAGE_SWEDISH, LOBBYAPI_COUNTRY_SWEDEN },
|
|
{ MAKELANGID(LANG_TAJIK, SUBLANG_TAJIK_TAJIKISTAN), LOBBYAPI_LANGUAGE_TAJIK, LOBBYAPI_COUNTRY_TAJIKISTAN },
|
|
{ MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_INDIA), LOBBYAPI_LANGUAGE_TAMIL, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_TATAR, SUBLANG_TATAR_RUSSIA), LOBBYAPI_LANGUAGE_TATAR, LOBBYAPI_COUNTRY_RUSSIAN_FEDERATION },
|
|
{ MAKELANGID(LANG_TELUGU, SUBLANG_TELUGU_INDIA), LOBBYAPI_LANGUAGE_TELUGU, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_THAI, SUBLANG_THAI_THAILAND), LOBBYAPI_LANGUAGE_THAI, LOBBYAPI_COUNTRY_THAILAND },
|
|
{ MAKELANGID(LANG_TIBETAN, SUBLANG_TIBETAN_PRC), LOBBYAPI_LANGUAGE_TIBETAN, LOBBYAPI_COUNTRY_CHINA },
|
|
{ MAKELANGID(LANG_TSWANA, SUBLANG_TSWANA_SOUTH_AFRICA), LOBBYAPI_LANGUAGE_SETSWANA, LOBBYAPI_COUNTRY_SOUTH_AFRICA },
|
|
{ MAKELANGID(LANG_TURKISH, SUBLANG_TURKISH_TURKEY), LOBBYAPI_LANGUAGE_TURKISH, LOBBYAPI_COUNTRY_TURKEY },
|
|
{ MAKELANGID(LANG_TURKMEN, SUBLANG_TURKMEN_TURKMENISTAN), LOBBYAPI_LANGUAGE_TURKMEN, LOBBYAPI_COUNTRY_TURKMENISTAN },
|
|
{ MAKELANGID(LANG_UIGHUR, SUBLANG_UIGHUR_PRC), LOBBYAPI_LANGUAGE_UIGHUR, LOBBYAPI_COUNTRY_CHINA },
|
|
{ MAKELANGID(LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE), LOBBYAPI_LANGUAGE_UKRAINIAN, LOBBYAPI_COUNTRY_UKRAINE },
|
|
{ MAKELANGID(LANG_URDU, SUBLANG_URDU_PAKISTAN), LOBBYAPI_LANGUAGE_URDU, LOBBYAPI_COUNTRY_PAKISTAN },
|
|
{ MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC), LOBBYAPI_LANGUAGE_UZBEK, LOBBYAPI_COUNTRY_UZBEKISTAN },
|
|
{ MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), LOBBYAPI_LANGUAGE_UZBEK, LOBBYAPI_COUNTRY_UZBEKISTAN },
|
|
{ MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM), LOBBYAPI_LANGUAGE_VIETNAMESE, LOBBYAPI_COUNTRY_VIETNAM },
|
|
{ MAKELANGID(LANG_WELSH, SUBLANG_WELSH_UNITED_KINGDOM), LOBBYAPI_LANGUAGE_WELSH, LOBBYAPI_COUNTRY_UNITED_KINGDOM },
|
|
{ MAKELANGID(LANG_WOLOF, SUBLANG_WOLOF_SENEGAL), LOBBYAPI_LANGUAGE_WOLOF, LOBBYAPI_COUNTRY_SENEGAL },
|
|
{ MAKELANGID(LANG_XHOSA, SUBLANG_XHOSA_SOUTH_AFRICA), LOBBYAPI_LANGUAGE_XHOSA, LOBBYAPI_COUNTRY_SOUTH_AFRICA },
|
|
{ MAKELANGID(LANG_YI, SUBLANG_YI_PRC), LOBBYAPI_LANGUAGE_YI, LOBBYAPI_COUNTRY_CHINA },
|
|
{ MAKELANGID(LANG_YORUBA, SUBLANG_YORUBA_NIGERIA), LOBBYAPI_LANGUAGE_YORUBA, LOBBYAPI_COUNTRY_NIGERIA },
|
|
{ MAKELANGID(LANG_ZULU, SUBLANG_ZULU_SOUTH_AFRICA), LOBBYAPI_LANGUAGE_ZULU, LOBBYAPI_COUNTRY_SOUTH_AFRICA },
|
|
{ MAKELANGID(0x91, SUBLANG_DEFAULT), LOBBYAPI_LANGUAGE_SCOTS_GAELIC, LOBBYAPI_COUNTRY_UNITED_KINGDOM },
|
|
// the following are valid Windows locales, but not covered by ISO639-1, LOBBYAPI_LANGUAGE_UNKNOWN will be returned for them.
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_INARI_FINLAND), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_FINLAND },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_LULE_NORWAY), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_NORWAY },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_LULE_SWEDEN), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_SWEDEN },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_SKOLT_FINLAND), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_FINLAND },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_SOUTHERN_NORWAY), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_NORWAY },
|
|
{ MAKELANGID(LANG_SAMI, SUBLANG_SAMI_SOUTHERN_SWEDEN), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_SWEDEN },
|
|
{ MAKELANGID(LANG_UPPER_SORBIAN, SUBLANG_UPPER_SORBIAN_GERMANY), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_GERMANY },
|
|
{ MAKELANGID(LANG_LOWER_SORBIAN, SUBLANG_LOWER_SORBIAN_GERMANY), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_GERMANY },
|
|
{ MAKELANGID(LANG_KONKANI, SUBLANG_KONKANI_INDIA), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_INDIA },
|
|
{ MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_SYRIAN_ARAB_REPUBLIC },
|
|
{ MAKELANGID(LANG_TAMAZIGHT, SUBLANG_NEUTRAL), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_ALGERIA },
|
|
{ MAKELANGID(LANG_TAMAZIGHT, SUBLANG_TAMAZIGHT_ALGERIA_LATIN), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_ALGERIA },
|
|
{ MAKELANGID(LANG_FILIPINO, SUBLANG_FILIPINO_PHILIPPINES), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_PHILIPPINES },
|
|
{ MAKELANGID(LANG_SOTHO, SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_SOUTH_AFRICA },
|
|
{ MAKELANGID(LANG_MAPUDUNGUN, SUBLANG_MAPUDUNGUN_CHILE), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_CHILE },
|
|
{ MAKELANGID(LANG_MOHAWK, SUBLANG_MOHAWK_MOHAWK), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_CANADA },
|
|
{ MAKELANGID(LANG_ALSATIAN, SUBLANG_ALSATIAN_FRANCE), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_FRANCE },
|
|
{ MAKELANGID(LANG_YAKUT, SUBLANG_YAKUT_RUSSIA), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_RUSSIAN_FEDERATION },
|
|
{ MAKELANGID(LANG_KICHE, SUBLANG_KICHE_GUATEMALA), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_GUATEMALA },
|
|
{ MAKELANGID(LANG_DARI, SUBLANG_DARI_AFGHANISTAN), LOBBYAPI_LANGUAGE_UNKNOWN, LOBBYAPI_COUNTRY_AFGHANISTAN }
|
|
};
|
|
|
|
//! global module ref
|
|
static NetConnRefT *_NetConn_pRef = NULL;
|
|
|
|
/*** Private Functions ****************************************************************************/
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _NetConnGetLocaleInfo
|
|
|
|
\Description
|
|
To obtain locale information for specified lang id.
|
|
|
|
\Input uLangId - the lang id used to extract locale info from
|
|
|
|
\Output
|
|
int32_t - the same output to NetConnStatus('locl'), ex. enUS
|
|
|
|
\Version 04/14/2011 (szhu)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _NetConnGetLocaleInfo(uint16_t uLangId)
|
|
{
|
|
uint16_t uLanguage, uCountry;
|
|
uint32_t uIndex;
|
|
|
|
// search the pre-defined mapping table
|
|
for (uIndex = 0; uIndex < (sizeof(_NetConn_WindowsLocaleMap)/sizeof(_NetConn_WindowsLocaleMap[0])); uIndex++)
|
|
{
|
|
// _NetConn_WindowsLocaleMap[uIndex][0]: LangId, [1]: language, [2]: COUNTRY
|
|
if (uLangId == _NetConn_WindowsLocaleMap[uIndex][0])
|
|
{
|
|
uLanguage = _NetConn_WindowsLocaleMap[uIndex][1];
|
|
uCountry = _NetConn_WindowsLocaleMap[uIndex][2];
|
|
return(LOBBYAPI_LocalizerTokenCreate(uLanguage, uCountry));
|
|
}
|
|
}
|
|
|
|
// not found in pre-defined mapping table, search again with SUBLANG_DEFAULT (only for SUBLANG_NEUTRAL)
|
|
if ((SUBLANGID(uLangId) == SUBLANG_NEUTRAL) && (SUBLANG_NEUTRAL != SUBLANG_DEFAULT))
|
|
{
|
|
uLangId = PRIMARYLANGID(uLangId);
|
|
return(_NetConnGetLocaleInfo(MAKELANGID(uLangId, SUBLANG_DEFAULT)));
|
|
}
|
|
|
|
NetPrintf(("netconnwin: failed to obtain locale info for localid (0x%04x), %s is returned.\n", (uint32_t)uLangId, LOBBYAPI_LOCALITY_UNKNOWN_STR));
|
|
// not found, zzZZ will be returned
|
|
return(LOBBYAPI_LOCALITY_UNKNOWN);
|
|
}
|
|
|
|
|
|
#if DIRTYCODE_LOGGING
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _NetConnVerifyLocale
|
|
|
|
\Description
|
|
Check if a _NetConn_WindowsLocaleMap entry is good by comparing with Windows API (GetLocaleInfo)'s result.
|
|
|
|
\Input *pLocale - a _NetConn_WindowsLocaleMap entry -- uint16_t[3]
|
|
\Input iAlwaysPrint - (boolean) TRUE, always prints debug trace; FALSE, prints debug trace upon error
|
|
|
|
\Output
|
|
int32_t - (boolean) TRUE=success, FALSE=failure
|
|
|
|
\Notes
|
|
For debugging purpose only.
|
|
|
|
\Version 03/25/2011 (szhu)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _NetConnVerifyLocale(uint16_t *pLocale, int32_t iAlwaysPrint)
|
|
{
|
|
int32_t iResult = FALSE;
|
|
char strLocale[LOCALE_NAME_MAX_LENGTH], strDefined[32];
|
|
char *pTemp1, *pTemp2;
|
|
uint32_t uToken;
|
|
|
|
// convert array to string like enUS
|
|
uToken = LOBBYAPI_LocalizerTokenCreate(pLocale[1], pLocale[2]);
|
|
LOBBYAPI_LocalizerTokenCreateLocalityString(strDefined, uToken);
|
|
|
|
// compare between mapping table value and Windows API GetLocaleInfo(LOCALE_SNAME) to verify whether the mapping table value is good.
|
|
ds_memclr(strLocale, sizeof(strLocale));
|
|
if (GetLocaleInfo(pLocale[0], LOCALE_SNAME, strLocale, LOCALE_NAME_MAX_LENGTH) > 0)
|
|
{
|
|
// GetLocaleInfo may return name-script-COUNTRY. If so, we remove the script: name-script-COUNTRY --> nameCOUNTRY
|
|
if ((pTemp1 = strchr(strLocale, '-')) != NULL)
|
|
{
|
|
// name-script-COUNTRY --> nameCOUNTRY
|
|
if ((pTemp2 = strchr(pTemp1 + 1, '-')) != NULL)
|
|
{
|
|
pTemp2++; // skip '-'
|
|
memmove(pTemp1, pTemp2, strlen(pTemp2) + 1); // plus '\0'
|
|
}
|
|
else // name-COUNTRY --> nameCOUNTRY
|
|
{
|
|
memmove(pTemp1, pTemp1 + 1, strlen(pTemp1 + 1) + 1);
|
|
}
|
|
}
|
|
|
|
// GetLocaleInfo may return name-COUNTRY_xxxx. If so, we remove _xxxx: nameCOUNTRY_xxxx --> nameCOUNTRY
|
|
if ((pTemp1 = strchr(strLocale, '_')) != NULL)
|
|
{
|
|
pTemp1[0] = 0;
|
|
}
|
|
|
|
// the language name should be in lowercase while the country name should be in uppercase.
|
|
// 1, enUS == enUS (perfect); 2, zzCA == xxxCA (not covered by ISO639-1); 3, xxCA == xxyCA (not covered by ISO639-1); 4, enZZ == enxxx;
|
|
if((strcmp(strDefined, strLocale) == 0)
|
|
|| (strncmp(strDefined, LOBBYAPI_LANGUAGE_UNKNOWN_STR, 2) == 0 && strncmp(strDefined + 2, strLocale + 3, 2) == 0)
|
|
|| (strncmp(strDefined, strLocale, 2) == 0 && strncmp(strDefined + 2, strLocale + 3, 2) == 0)
|
|
|| (strncmp(strDefined, strLocale, 2) == 0 && strncmp(strDefined + 2, LOBBYAPI_COUNTRY_UNKNOWN_STR, 2) == 0 && strlen(strLocale) != 4))
|
|
{
|
|
// check if _NetConnGetLocaleInfo behaves correctly
|
|
if ((uint32_t)_NetConnGetLocaleInfo(pLocale[0]) == uToken)
|
|
{
|
|
iResult = TRUE;
|
|
if (iAlwaysPrint != FALSE)
|
|
{
|
|
NetPrintf(("netconnwin: passed -- GetLocaleInfo(0x%04x) returned (%s)!\n", (uint32_t)pLocale[0], strLocale));
|
|
}
|
|
// if not perfect (enUS == enUS), print debug trace
|
|
if (strcmp(strDefined, strLocale) != 0)
|
|
{
|
|
NetPrintf(("netconnwin: notice -- GetLocaleInfo(0x%04x) returned (%s) - (%s)!\n", (uint32_t)pLocale[0], strLocale, strDefined));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (iResult == FALSE)
|
|
{
|
|
NetPrintf(("netconnwin: ERROR -- GetLocaleInfo(0x%04x) returned (%s) - (%s)!\n", (uint32_t)pLocale[0], strLocale, strDefined));
|
|
}
|
|
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _NetConnVerifyAllLocales
|
|
|
|
\Description
|
|
Verify if _NetConn_WindowsLocaleMap items are good. For debugging purpose only.
|
|
|
|
\Notes
|
|
For unknown language, zz will be returned;
|
|
For unknown country, ZZ will be returned;
|
|
For unknown locality, zzZZ will be returned.
|
|
|
|
\Version 03/25/2011 (szhu)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _NetConnVerifyAllLocales(void)
|
|
{
|
|
uint16_t aNeutral[3];
|
|
uint32_t uIndex, uToken;
|
|
char strLocale[LOCALE_NAME_MAX_LENGTH];
|
|
|
|
for (uIndex = 0; uIndex < (sizeof(_NetConn_WindowsLocaleMap)/sizeof(_NetConn_WindowsLocaleMap[0])); uIndex++)
|
|
{
|
|
if (_NetConnVerifyLocale(_NetConn_WindowsLocaleMap[uIndex], FALSE) == FALSE)
|
|
{
|
|
NetPrintf(("netconnwin: error found in _NetConn_WindowsLocaleMap[%u] (0x%04x)!\n", uIndex, (uint32_t)_NetConn_WindowsLocaleMap[uIndex][0]));
|
|
DebugBreak();
|
|
}
|
|
|
|
// verify if langid(Primary ID, SUBLANG_NEUTRAL) works out
|
|
// exception 0x0404: 0x0404 --> ZH_TW, 0x0004 --> ZH_CN
|
|
if ((_NetConn_WindowsLocaleMap[uIndex][0] != 0x0404) && (SUBLANGID(_NetConn_WindowsLocaleMap[uIndex][0]) == SUBLANG_DEFAULT))
|
|
{
|
|
aNeutral[0] = MAKELANGID(PRIMARYLANGID(_NetConn_WindowsLocaleMap[uIndex][0]), SUBLANG_NEUTRAL);
|
|
aNeutral[1] = _NetConn_WindowsLocaleMap[uIndex][1];
|
|
aNeutral[2] = _NetConn_WindowsLocaleMap[uIndex][2];
|
|
|
|
if (_NetConnVerifyLocale(aNeutral, FALSE) == FALSE)
|
|
{
|
|
NetPrintf(("netconnwin: error found in _NetConn_WindowsLocaleMap[%u](Neutral) (0x%04x)!\n", uIndex, (uint32_t)aNeutral[0]));
|
|
DebugBreak();
|
|
}
|
|
}
|
|
}
|
|
NetPrintf(("netconnwin: checked _NetConn_WindowsLocaleMap -- %u entries in total.\n", uIndex));
|
|
|
|
// print locale information
|
|
uToken = NetConnStatus('locl', 0, NULL, 0);
|
|
NetPrintf(("netconnwin: locality returned by NetConnStatus(locl,0): (%c%c%c%c).\n", LOBBYAPI_LocalizerTokenPrintCharArray(uToken)));
|
|
|
|
// test if _NetConnGetLocaleInfo works fine when given an invalid langid
|
|
uToken = _NetConnGetLocaleInfo(0x9FFF);
|
|
NetPrintf(("netconnwin: _NetConnGetLocaleInfo(0x9FFF) returned: (%c%c%c%c) - (%s).\n", LOBBYAPI_LocalizerTokenPrintCharArray(uToken), LOBBYAPI_LOCALITY_UNKNOWN_STR));
|
|
|
|
// list locales that not covered by the mapping table
|
|
for (uIndex = 1; uIndex <= 0x8200; uIndex++)
|
|
{
|
|
if ((PRIMARYLANGID(uIndex) == LANG_NEUTRAL)
|
|
|| (uIndex == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL))
|
|
|| (uIndex == MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ((GetLocaleInfo(uIndex, LOCALE_SNAME, strLocale, LOCALE_NAME_MAX_LENGTH) > 0)
|
|
&& (_NetConnGetLocaleInfo(uIndex) == 'zzZZ'))
|
|
{
|
|
NetPrintf(("netconnwin: not covered (0x%04x): %s!\n", uIndex, strLocale));
|
|
}
|
|
}
|
|
}
|
|
#endif //DIRTYCODE_LOGGING
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _NetConnIsValidMacAddress
|
|
|
|
\Description
|
|
Checks to make sure the address is valid
|
|
|
|
\Input *pAddr - The current address we are checking for validity
|
|
\Input bCheckIP - Should we check the IP Address of the NIC to make sure it is active
|
|
|
|
\Output
|
|
uint8_t - TRUE=valid, FALSE=invalid
|
|
*/
|
|
/********************************************************************************F*/
|
|
static uint8_t _NetConnIsValidMacAddress(PIP_ADAPTER_ADDRESSES pAddr, uint8_t bCheckIP)
|
|
{
|
|
PIP_ADAPTER_UNICAST_ADDRESS pUnicastAddr;
|
|
|
|
// If the address is not 6-byte long it is invalid
|
|
if (pAddr->PhysicalAddressLength != 6)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// If we are not checking the IP address then the MAC is valid
|
|
// as far as we are concerned
|
|
if (bCheckIP == FALSE)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// Make sure the address has a valid IP in multiple NIC situation
|
|
for (pUnicastAddr = pAddr->FirstUnicastAddress; pUnicastAddr != NULL; pUnicastAddr = pUnicastAddr->Next)
|
|
{
|
|
if ((pUnicastAddr->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE) == IP_ADAPTER_ADDRESS_DNS_ELIGIBLE)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _NetConnFindMacAddress
|
|
|
|
\Description
|
|
Scans through adapter list and finds an active adapter.
|
|
|
|
\Input *pMacAddr - user-provided buffer to be filled with MAC address
|
|
\Input iAddrSize - The size of the buffer
|
|
\Input bCheckIP - If we should check for a valid IP on the NIC
|
|
|
|
\Output
|
|
int32_t - Negative=error, zero=success
|
|
|
|
\Version 06/23/2009 (mclouatre)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _NetConnFindMacAddress(uint8_t *pMacAddr, int32_t iAddrSize, uint8_t bCheckIP)
|
|
{
|
|
NetConnRefT *pRef = _NetConn_pRef;
|
|
DWORD dwMsRetVal;
|
|
ULONG ulOutBufLen;
|
|
ULONG ulDummyBuffer;
|
|
PIP_ADAPTER_ADDRESSES pAdaptersAddrBuf;
|
|
PIP_ADAPTER_ADDRESSES pCurrAddr;
|
|
|
|
#if DIRTYCODE_LOGGING
|
|
uint32_t uByteIndex;
|
|
char strPrintBuf[32];
|
|
int32_t iCurrLen;
|
|
#endif
|
|
|
|
int32_t iRetVal = 0;
|
|
|
|
// make an initial call to GetAdaptersAddresses() to get the
|
|
// size needed into the ulOutBufLen variable
|
|
ulOutBufLen = 1; // make sure that size provided is too small to store the info.
|
|
dwMsRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, (PIP_ADAPTER_ADDRESSES) &ulDummyBuffer, &ulOutBufLen);
|
|
if (dwMsRetVal != ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
// if windows does not return an overflow error, something is wrong...
|
|
NetPrintf(("netconnwin: GetAdaptersAddresses() failed with err %d when querying for output buffer size\n", dwMsRetVal));
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
allocate a big enough buffer.
|
|
note:
|
|
* it is not a good idea to preallocate this as we will have to seriously overallocate to support rare cases
|
|
with a long list of IP_ADAPTER_ADDRESSES returned. MS doc states that Windows will "typically" not
|
|
require a buffer larger than 15 Kbytes http://msdn.microsoft.com/en-us/library/aa365915(VS.85).aspx
|
|
* it is not a good idea to allocate this buffer on the stack as it can be quite huge and could lead to a
|
|
stack overflow.
|
|
*/
|
|
if ((pAdaptersAddrBuf = DirtyMemAlloc(ulOutBufLen, NETCONN_MEMID, pRef->Common.iMemGroup, pRef->Common.pMemGroupUserData)) == NULL)
|
|
{
|
|
NetPrintf(("netconnwin: unable to allocate output buffer required to call GetAdaptersAddresses()\n"));
|
|
return(-2);
|
|
}
|
|
|
|
// make a second call to GetAdaptersAddresses() to get the actual data we want
|
|
dwMsRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAdaptersAddrBuf, &ulOutBufLen);
|
|
if (dwMsRetVal == NO_ERROR)
|
|
{
|
|
// loop through the adapters and match first entry with valid MAC address
|
|
pCurrAddr = pAdaptersAddrBuf;
|
|
while (pCurrAddr)
|
|
{
|
|
// make sure interface type can have a MAC address
|
|
if ((pCurrAddr->IfType == IF_TYPE_ETHERNET_CSMACD) || (pCurrAddr->IfType == IF_TYPE_IEEE80211))
|
|
{
|
|
// make sure physical address is 6-byte long and has a valid ip address; if not, it is not a MAC address
|
|
if (_NetConnIsValidMacAddress(pCurrAddr, bCheckIP) == TRUE)
|
|
{
|
|
ds_memcpy_s(pMacAddr, iAddrSize, pCurrAddr->PhysicalAddress, pCurrAddr->PhysicalAddressLength);
|
|
|
|
#if DIRTYCODE_LOGGING
|
|
// We need to use sprintf here because if we try to NetPrintf we will
|
|
// have timestamps inbetween where we are printing out the mac address
|
|
|
|
ds_memclr(strPrintBuf, sizeof(strPrintBuf));
|
|
iCurrLen = 0;
|
|
|
|
for (uByteIndex = 0; uByteIndex < (int32_t) pCurrAddr->PhysicalAddressLength; uByteIndex++)
|
|
{
|
|
if (uByteIndex == (pCurrAddr->PhysicalAddressLength - 1))
|
|
{
|
|
iCurrLen += ds_snzprintf(strPrintBuf + iCurrLen, sizeof(strPrintBuf) - iCurrLen, "%.2X", (int32_t)pCurrAddr->PhysicalAddress[uByteIndex]);
|
|
}
|
|
else
|
|
{
|
|
iCurrLen += ds_snzprintf(strPrintBuf + iCurrLen, sizeof(strPrintBuf) - iCurrLen, "%.2X-", (int32_t)pCurrAddr->PhysicalAddress[uByteIndex]);
|
|
}
|
|
}
|
|
|
|
NetPrintf(("netconnwin: valid MAC address found --> %s\n", strPrintBuf));
|
|
#endif
|
|
|
|
// valid MAC address found! exit the function with success
|
|
break;
|
|
}
|
|
}
|
|
|
|
pCurrAddr = pCurrAddr->Next;
|
|
}
|
|
|
|
if (pCurrAddr == NULL)
|
|
{
|
|
NetPrintf(("netconnwin: could not find any valid adapters to get a MAC address from\n"));
|
|
iRetVal = -3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("netconnwin: GetAdaptersAddresses() failed with err %d when querying for adapters data size\n", dwMsRetVal));
|
|
iRetVal = -4;
|
|
}
|
|
|
|
// free buffer used with GetAdaptersAddresses
|
|
DirtyMemFree(pAdaptersAddrBuf, NETCONN_MEMID, pRef->Common.iMemGroup, pRef->Common.pMemGroupUserData);
|
|
|
|
return(iRetVal);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _NetConnShutdownInternal
|
|
|
|
\Description
|
|
Shutdown the network code and return to idle state for internal use
|
|
|
|
\Input pRef - netconn ref
|
|
\Input bStopEE - ignored in PC implementation
|
|
|
|
\Output
|
|
int32_t - negative=error, else zero
|
|
|
|
\Version 1/13/2020 (tcho)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t _NetConnShutdownInternal(NetConnRefT *pRef, uint32_t bStopEE)
|
|
{
|
|
int32_t iResult = 0;
|
|
|
|
// decrement and check the refcount
|
|
if ((iResult = NetConnCommonCheckRef((NetConnCommonRefT*)pRef)) < 0)
|
|
{
|
|
return(iResult);
|
|
}
|
|
|
|
if (_NetConn_pRef != NULL)
|
|
{
|
|
NetConnDisconnect();
|
|
}
|
|
|
|
// destroy the upnp ref
|
|
if (pRef->pProtoUpnp != NULL)
|
|
{
|
|
ProtoUpnpDestroy(pRef->pProtoUpnp);
|
|
pRef->pProtoUpnp = NULL;
|
|
}
|
|
|
|
// shut down protossl
|
|
ProtoSSLShutdown();
|
|
|
|
// shut down dirtycert
|
|
DirtyCertDestroy();
|
|
|
|
// shut down Idle handler
|
|
NetConnIdleShutdown();
|
|
|
|
// shut down dirtysock
|
|
SocketDestroy(0);
|
|
|
|
// common shutdown (must come last as this frees the memory)
|
|
NetConnCommonShutdown(&pRef->Common);
|
|
_NetConn_pRef = NULL;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*** Public functions *****************************************************************************/
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function NetConnStartup
|
|
|
|
\Description
|
|
Bring the network connection module to life. Does not actually start any
|
|
network activity.
|
|
|
|
\Input *pParams - startup parameters
|
|
|
|
\Output
|
|
int32_t - zero=success, negative=failure
|
|
|
|
\Notes
|
|
NetConnRefT::iRefCount serves as a counter for the number of times
|
|
NetConnStartup has been called. This allows us to track how many modules
|
|
are using it and how many times we expect NetConnShutdown to the called.
|
|
In the past we only allowed a single call to NetConnStartup but some
|
|
libraries may need to networking without a guarentee that the game has
|
|
already started it.
|
|
|
|
pParams can contain the following terms:
|
|
|
|
\verbatim
|
|
-noupnp : disable UPNP
|
|
-servicename=<game-year-platform> : set servicename required for SSL use
|
|
-affinity=<mask as hex> : cpu affinity we set for our internal threads
|
|
\endverbatim
|
|
|
|
\Version 3/10/01 (GWS)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t NetConnStartup(const char *pParams)
|
|
{
|
|
NetConnRefT *pRef = _NetConn_pRef;
|
|
int32_t iResult = 0;
|
|
char strThreadCpuAffinity[16];
|
|
|
|
// allow NULL params
|
|
if (pParams == NULL)
|
|
{
|
|
pParams = "";
|
|
}
|
|
|
|
// debug display of input params
|
|
NetPrintf(("netconnwin: startup params='%s'\n", pParams));
|
|
|
|
// common startup
|
|
// pRef shall hold the address of the NetConnRefT after completion if no error occured
|
|
iResult = NetConnCommonStartup(sizeof(*pRef), pParams, (NetConnCommonRefT**)(&pRef));
|
|
|
|
// treat the result of the common startup, if already started simply early out
|
|
if (iResult == NETCONN_ERROR_ALREADY_STARTED)
|
|
{
|
|
return(0);
|
|
}
|
|
// otherwise, if an error occured report it
|
|
else if (iResult < 0)
|
|
{
|
|
return(iResult);
|
|
}
|
|
|
|
pRef->eState = ST_INIT;
|
|
pRef->iPeerPort = NETCONN_DEFAULT_UPNP_PORT;
|
|
|
|
// get the cpu affinity string from our startup params, defaulting to 0x0
|
|
ds_memclr(strThreadCpuAffinity, sizeof(strThreadCpuAffinity));
|
|
NetConnCopyParam(strThreadCpuAffinity, sizeof(strThreadCpuAffinity), "-affinity=", pParams, "0x0");
|
|
pRef->iThreadCpuAffinity = strtol(strThreadCpuAffinity, NULL, 16);
|
|
|
|
// start up dirtysock
|
|
if (SocketCreate(THREAD_PRIORITY_HIGHEST, 0, pRef->iThreadCpuAffinity) != 0)
|
|
{
|
|
_NetConnShutdownInternal(pRef, FALSE);
|
|
NetPrintf(("netconnwin: unable to start up dirtysock\n"));
|
|
return(NETCONN_ERROR_SOCKET_CREATE);
|
|
}
|
|
|
|
// create and configure dirtycert
|
|
if (NetConnDirtyCertCreate(pParams))
|
|
{
|
|
_NetConnShutdownInternal(pRef, FALSE);
|
|
NetPrintf(("netconnwin: unable to create dirtycert\n"));
|
|
return(NETCONN_ERROR_DIRTYCERT_CREATE);
|
|
}
|
|
|
|
// start up protossl
|
|
if (ProtoSSLStartup() < 0)
|
|
{
|
|
_NetConnShutdownInternal(pRef, FALSE);
|
|
NetPrintf(("netconnwin: unable to start up protossl\n"));
|
|
return(NETCONN_ERROR_PROTOSSL_CREATE);
|
|
}
|
|
|
|
if (strstr(pParams, "-noupnp") == NULL)
|
|
{
|
|
pRef->pProtoUpnp = ProtoUpnpCreate();
|
|
if (pRef->pProtoUpnp == NULL)
|
|
{
|
|
_NetConnShutdownInternal(pRef, FALSE);
|
|
NetPrintf(("netconnwin: unable to start up protoupnp\n"));
|
|
return(NETCONN_ERROR_PROTOUPNP_CREATE);
|
|
}
|
|
}
|
|
|
|
// save ref
|
|
_NetConn_pRef = pRef;
|
|
|
|
#if DIRTYCODE_LOGGING
|
|
// if we made changes to the mapping table (_NetConn_WindowsLocaleMap),
|
|
// uncomment the following line and build-debug-run to verify if the changes are good.
|
|
//_NetConnVerifyAllLocales();
|
|
#endif
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function NetConnQuery
|
|
|
|
\Description
|
|
Query the list of available connection configurations. This list is loaded
|
|
from the specified device. The list is returned in a simple fixed width
|
|
array with one string per array element. The caller can find the user portion
|
|
of the config name via strchr(item, '#')+1.
|
|
|
|
\Input *pDevice - device to scan (mc0:, mc1:, pfs0:, pfs1:)
|
|
\Input *pList - buffer to store output array in
|
|
\Input iSize - length of buffer in bytes
|
|
|
|
\Output
|
|
int32_t - negative=error, else number of configurations
|
|
|
|
\Version 01/18/02 (GWS)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
int32_t NetConnQuery(const char *pDevice, NetConfigRecT *pList, int32_t iSize)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function NetConnConnect
|
|
|
|
\Description
|
|
Used to bring the networking online with a specific configuration. Uses the
|
|
configuration returned by NetConnQuery.
|
|
|
|
\Input *pConfig - the configuration entry from NetConnQuery
|
|
\Input *pOption - asciiz list of config parameters
|
|
"peerport=<port>" to specify peer port to be opened by upnp.
|
|
\Input iData - platform-specific
|
|
|
|
\Output
|
|
int32_t - negative=error, zero=success
|
|
|
|
\Version 01/18/02 (GWS)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
int32_t NetConnConnect(const NetConfigRecT *pConfig, const char *pOption, int32_t iData)
|
|
{
|
|
NetConnRefT *pRef = _NetConn_pRef;
|
|
|
|
// check connection options, if present
|
|
if (pOption != NULL)
|
|
{
|
|
const char *pOpt;
|
|
// check for specification of peer port
|
|
if ((pOpt = strstr(pOption, "peerport=")) != NULL)
|
|
{
|
|
pRef->iPeerPort = strtol(pOpt+9, NULL, 10);
|
|
}
|
|
}
|
|
NetPrintf(("netconnwin: upnp peerport=%d %s\n",
|
|
pRef->iPeerPort, (pRef->iPeerPort == NETCONN_DEFAULT_UPNP_PORT ? "(default)" : "(selected via netconnconnect param)")));
|
|
|
|
// make sure we aren't already connected
|
|
if (pRef->eState == ST_INIT)
|
|
{
|
|
// connecting
|
|
pRef->eState = ST_CONN;
|
|
|
|
// discover upnp router information
|
|
if (pRef->pProtoUpnp != NULL)
|
|
{
|
|
if (pRef->iPeerPort != 0)
|
|
{
|
|
ProtoUpnpControl(pRef->pProtoUpnp, 'port', pRef->iPeerPort, 0, NULL);
|
|
ProtoUpnpControl(pRef->pProtoUpnp, 'macr', 'upnp', 0, NULL);
|
|
}
|
|
else
|
|
{
|
|
ProtoUpnpControl(pRef->pProtoUpnp, 'macr', 'dscg', 0, NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetPrintf(("netconnwin: NetConnConnect() ignored because already connected!\n"));
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function NetConnDisconnect
|
|
|
|
\Description
|
|
Used to bring down the network connection. After calling this, it would
|
|
be necessary to call NetConnConnect to bring the connection back up or
|
|
NetConnShutdown to completely shutdown all network support.
|
|
|
|
\Output
|
|
int32_t - negative=error, zero=success
|
|
|
|
\Version 02/09/02 (GWS)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
int32_t NetConnDisconnect(void)
|
|
{
|
|
NetConnRefT *pRef = _NetConn_pRef;
|
|
|
|
if (pRef->eState == ST_CONN)
|
|
{
|
|
// shutdown the interfaces (but leave API running)
|
|
pRef->eState = ST_INIT;
|
|
}
|
|
|
|
// abort upnp operations
|
|
if (pRef->pProtoUpnp != NULL)
|
|
{
|
|
ProtoUpnpControl(pRef->pProtoUpnp, 'abrt', 0, 0, NULL);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function NetConnControl
|
|
|
|
\Description
|
|
Set module behavior based on input selector.
|
|
|
|
\Input iControl - input selector
|
|
\Input iValue - selector input
|
|
\Input iValue2 - selector input
|
|
\Input *pValue - selector input
|
|
\Input *pValue2 - selector input
|
|
|
|
\Output
|
|
int32_t - selector result
|
|
|
|
\Notes
|
|
iControl can be one of the following:
|
|
|
|
\verbatim
|
|
snam: set DirtyCert service name
|
|
\endverbatim
|
|
|
|
Unhandled selectors are passed through to NetConnCommonControl()
|
|
|
|
\Version 04/27/2006 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t NetConnControl(int32_t iControl, int32_t iValue, int32_t iValue2, void *pValue, void *pValue2)
|
|
{
|
|
NetConnRefT *pRef = _NetConn_pRef;
|
|
|
|
// make sure module is started before allowing any other control calls
|
|
if (pRef == NULL)
|
|
{
|
|
NetPrintf(("netconnwin: warning - calling NetConnControl() while module is not initialized\n"));
|
|
return(-1);
|
|
}
|
|
|
|
// set dirtycert service name
|
|
if (iControl == 'snam')
|
|
{
|
|
return(DirtyCertControl('snam', 0, 0, pValue));
|
|
}
|
|
|
|
// pass through unhandled selectors to NetConnCommon
|
|
return(NetConnCommonControl(&pRef->Common, iControl, iValue, iValue2, pValue, pValue2));
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function NetConnStatus
|
|
|
|
\Description
|
|
Check general network connection status. Different selectors return
|
|
different status attributes.
|
|
|
|
\Input iKind - status selector
|
|
\Input iData - (optional) selector specific
|
|
\Input *pBuf - (optional) pointer to output buffer
|
|
\Input iBufSize - (optional) size of output buffer
|
|
|
|
\Output
|
|
int32_t - selector specific
|
|
|
|
\Notes
|
|
iKind can be one of the following:
|
|
|
|
\verbatim
|
|
addr: ip address of client
|
|
affn: get the thread cpu affinity setting
|
|
bbnd: broadband true or false
|
|
conn: true/false indication of whether connection in progress
|
|
ethr: mac address of adapter based on iData (0=first, otherwise=first active) (returned in pBuf), 0=success, negative=error
|
|
locl: return locality (Windows locale) for local system, ex. 'enUS'
|
|
For unrecognized locale, 'zzZZ' will be returned.
|
|
locn: return location (Windows location) for local system, ex. 'zzCA'
|
|
The language part of the return value should be ignored by the caller.
|
|
If local system has 'no location' set, 'zzZZ' will be returned.
|
|
macx: mac address of adapter based on iData (0=first, otherwise=first active) (returned in pBuf), 0=success, negative=error
|
|
onln: true/false indication of whether network is operational
|
|
open: true/false indication of whether network code running
|
|
type: NETCONN_IFTYPE_*
|
|
upnp: return protoupnp port info, if available
|
|
vers: return DirtySDK version
|
|
\endverbatim
|
|
|
|
Unhandled selectors are passed through to NetConnCommonStatus()
|
|
|
|
\Version 03/10/2001 (gschaefer)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
int32_t NetConnStatus(int32_t iKind, int32_t iData, void *pBuf, int32_t iBufSize)
|
|
{
|
|
NetConnRefT *pRef = _NetConn_pRef;
|
|
|
|
// see if network code is initialized
|
|
if (iKind == 'open')
|
|
{
|
|
return(pRef != NULL);
|
|
}
|
|
// return DirtySDK version
|
|
if (iKind == 'vers')
|
|
{
|
|
return(DIRTYSDK_VERSION);
|
|
}
|
|
|
|
// make sure module is started before allowing any other status calls
|
|
if (pRef == NULL)
|
|
{
|
|
NetPrintf(("netconn: warning - calling NetConnStatus() while module is not initialized\n"));
|
|
return(-1);
|
|
}
|
|
|
|
// return client ip address
|
|
if (iKind == 'addr')
|
|
{
|
|
return(SocketGetLocalAddr());
|
|
}
|
|
|
|
// return the thread cpu affinity
|
|
if (iKind == 'affn')
|
|
{
|
|
return(pRef->iThreadCpuAffinity);
|
|
}
|
|
|
|
// return whether we are broadband or not
|
|
if (iKind == 'bbnd')
|
|
{
|
|
// assume broadband
|
|
return(TRUE);
|
|
}
|
|
|
|
// return connection status
|
|
if (iKind == 'conn')
|
|
{
|
|
return((pRef->eState == ST_CONN) ? '+onl' : '-dsc');
|
|
}
|
|
|
|
// return host mac address
|
|
if ((iKind == 'ethr') || (iKind == 'macx'))
|
|
{
|
|
if (pBuf != NULL)
|
|
{
|
|
// clear out the buffer
|
|
ds_memclr(pBuf, iBufSize);
|
|
|
|
// find a valid MAC address
|
|
return(_NetConnFindMacAddress(pBuf, iBufSize, iData == 0 ? FALSE : TRUE));
|
|
}
|
|
}
|
|
|
|
// see if connected to ISP/LAN
|
|
if (iKind == 'onln')
|
|
{
|
|
return(pRef->eState == ST_CONN);
|
|
}
|
|
|
|
// return what type of interface we are connected with
|
|
if (iKind == 'type')
|
|
{
|
|
// assume broadband
|
|
return(NETCONN_IFTYPE_ETHER);
|
|
}
|
|
|
|
// return upnp addportmap info, if available
|
|
if (iKind == 'upnp')
|
|
{
|
|
// if protoupnp is available, and we've added a port map, return the external port for the port mapping
|
|
if ((pRef->pProtoUpnp != NULL) && (ProtoUpnpStatus(pRef->pProtoUpnp, 'stat', NULL, 0) & PROTOUPNP_STATUS_ADDPORTMAP))
|
|
{
|
|
return(ProtoUpnpStatus(pRef->pProtoUpnp, 'extp', NULL, 0));
|
|
}
|
|
}
|
|
|
|
// return Windows locale information
|
|
if (iKind == 'locl')
|
|
{
|
|
return(_NetConnGetLocaleInfo(GetUserDefaultLangID()));
|
|
}
|
|
|
|
// return Windows location information
|
|
if (iKind == 'locn')
|
|
{
|
|
GEOID iGeoID;
|
|
char strCountry[8]; // ISO2, [8] is enough
|
|
uint16_t uLanguage = LOBBYAPI_LANGUAGE_UNKNOWN, // language is always set to zz
|
|
uCountry = LOBBYAPI_COUNTRY_UNKNOWN; // default to ZZ
|
|
|
|
// check if local system has location set
|
|
if ((iGeoID = GetUserGeoID(GEOCLASS_NATION)) == GEOID_NOT_AVAILABLE)
|
|
{
|
|
return(LOBBYAPI_LOCALITY_UNKNOWN);
|
|
}
|
|
|
|
ds_memclr(strCountry, sizeof(strCountry));
|
|
if ((GetGeoInfoA(iGeoID, GEO_ISO2, strCountry, sizeof(strCountry), 0) > 0)
|
|
&& (strlen(strCountry) == sizeof(uint16_t))
|
|
&& (ds_stricmp(strCountry, NETCONNWIN_COUNTRY_UNKNOWN_STR) != 0))
|
|
{
|
|
// a valid country code: 2-letter, and not equal to XX
|
|
uCountry = LOBBYAPI_LocalizerTokenGetShortFromString(strCountry);
|
|
}
|
|
|
|
return(LOBBYAPI_LocalizerTokenCreate(uLanguage, uCountry));
|
|
}
|
|
|
|
// pass unrecognized options to NetConnCommon
|
|
return(NetConnCommonStatus(&pRef->Common, iKind, iData, pBuf, iBufSize));
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function NetConnShutdown
|
|
|
|
\Description
|
|
Shutdown the network code and return to idle state.
|
|
|
|
\Input bStopEE - ignored in PC implementation
|
|
|
|
\Output
|
|
negative=error, zero=success
|
|
|
|
\Version 3/10/01 (GWS)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
int32_t NetConnShutdown(uint32_t bStopEE)
|
|
{
|
|
NetConnRefT *pRef = _NetConn_pRef;
|
|
|
|
// error see if already stopped
|
|
if (pRef == NULL)
|
|
{
|
|
return(NETCONN_ERROR_NOTACTIVE);
|
|
}
|
|
|
|
return(_NetConnShutdownInternal(pRef, bStopEE));
|
|
}
|
|
|
|
/*F*************************************************************************************************/
|
|
/*!
|
|
\Function NetConnSleep
|
|
|
|
\Description
|
|
Sleep the application (yield thread) for some number of milliseconds.
|
|
|
|
\Input iMilliSecs - number of milliseconds to block for
|
|
|
|
\Output
|
|
None
|
|
|
|
\Version 04/30/02 (GWS)
|
|
*/
|
|
/*************************************************************************************************F*/
|
|
void NetConnSleep(int32_t iMilliSecs)
|
|
{
|
|
Sleep(iMilliSecs);
|
|
}
|