/*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 #pragma warning(pop) #include #include // for GetAdaptersAddresses() #include // for PIP_ADAPTER_ADDRESSES #include // 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= : set servicename required for SSL use -affinity= : 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=" 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); }