Valhalla Legends Forums Archive | Battle.net Bot Development | Help with initial logon sequence and message 0x50 (C++)

AuthorMessageTime
Win32
Hi,
First question I have is, what is the very first message to be sent to the server? I gather it's the protocol identifier byte, but I'm not certain. And in what format is the protocol identifier byte sent to the server?

Secondly, does my construct (below) of the 0x50 message appear correct?

P.S; After awhile I'll receive 4 bytes, this will occur a variable number of times with the interval being around 30 seconds.

[code]
struct SID_AUTH_INFO
{
Byte  Header;
Byte  MessageId;
Word  wLength;
Dword dwProtocolId;
Dword dwPlatformId;
Dword dwProductId;
Dword dwVersion;
Dword dwProductLanguage;
Dword dwLocalIp;
Dword dwTimeZoneBias;
Dword dwLocaleId;
Dword dwLanguageId;
Char  strCountryAbbrv[4];
Char  strCountry[10];
} Packet;


Packet.Header            = 0xFF;
Packet.MessageId         = 0x50;
Packet.wLength           = sizeof(SID_AUTH_INFO);
Packet.dwProtocolId      = 0x0;
Packet.dwPlatformId      = '68XI';
Packet.dwProductId       = 'RATS';
Packet.dwVersion         = 0xCD;
Packet.dwProductLanguage = 0;
Packet.dwLocalIp         = inet_addr("192.168.0.2");
Packet.dwTimeZoneBias    = 600;
Packet.dwLocaleId        = 0;
Packet.dwLanguageId      = (Dword) GetUserDefaultLangID();
strcpy(Packet.strCountryAbbrv, "Aus");
strcpy(Packet.strCountry, "Australia");
[/code]


I've been running some simple tests which look like the following; (I apologize for the sloppness of the code within main, just debugging)

[code]
void main()
{
bThreadIsIdle = FALSE;
bSuspendThread = FALSE;


WSAData WSI;
ZeroMemory(&BnetSockAddress, sizeof(SOCKADDR_IN));
ZeroMemory(&BnetHostAddress, sizeof(SOCKADDR_IN));

BnetSockAddress.sin_family = AF_INET;

BnetHostAddress.sin_family = AF_INET;
BnetHostAddress.sin_addr.s_addr = inet_addr("63.240.202.130");
BnetHostAddress.sin_port = htons(6112);

WSAStartup(MAKEWORD(2, 2), &WSI);


struct SID_AUTH_INFO
{
Byte  Header;
Byte  MessageId;
Word  wLength;
Dword dwProtocolId;
Dword dwPlatformId;
Dword dwProductId;
Dword dwVersion;
Dword dwProductLanguage;
Dword dwLocalIp;
Dword dwTimeZoneBias;
Dword dwLocaleId;
Dword dwLanguageId;
Char  strCountryAbbrv[4];
Char  strCountry[10];
} Packet;


Packet.Header            = 0xFF;
Packet.MessageId         = 0x50;
Packet.wLength           = sizeof(SID_AUTH_INFO);
Packet.dwProtocolId      = 0x0;
Packet.dwPlatformId      = '68XI';
Packet.dwProductId       = 'RATS';
Packet.dwVersion         = 0xCD;
Packet.dwProductLanguage = 0;
Packet.dwLocalIp         = inet_addr("192.168.0.2");
Packet.dwTimeZoneBias    = 600;
Packet.dwLocaleId        = 0;
Packet.dwLanguageId      = (Dword) GetUserDefaultLangID();
strcpy(Packet.strCountryAbbrv, "Aus");
strcpy(Packet.strCountry, "Australia");


if(InitBnetSocket())
{
std::cout << "Created Battle.net socket" << std::endl;

if(ConnectToBnet())
{
std::cout << "Connected to Battle.net" << std::endl;

Dword Protocol = 0x01;

std::cout << "Sent: " << send(hBnetSocket, (const char*) "\x1", 1, NULL) << std::endl;
std::cout << "Sent: " << send(hBnetSocket, (const char*) &Packet, sizeof(SID_AUTH_INFO), NULL) << std::endl;

ProcessIncommingData(NULL);


closesocket(hBnetSocket);
}

else std::cout << "Failed to connect to Battle.net" << std::endl;
}

else std::cout << "Failed to create Battle.net socket.";

WSACleanup();


char x;
std::cin >> x;
}
[/code]


And the code as a whole if it's relevent;
BnetDiag.h
[code]
/*
* BnetDiag.h
* ==========
* Copyright (C) Matthew J. W.
* All rights reserved.
* Version 1.0
*
*
* Description:
*   Master include file for the "Battle.net Diagnostic Tool"
*   project.
*
*
************************************************************************************************************************/
#define _WIN32_WINNT  0x0400



//----------------------------------------------------------
// Marcos
//----------------------------------------------------------
#define SOCKET_BUFFER_SIZE  512


//----------------------------------------------------------
// System Includes
//----------------------------------------------------------
#include <winsock2.h> // Windows Sockets API.
#include <windows.h>  // Windows API.


//----------------------------------------------------------
// Fundamental Types
//----------------------------------------------------------
typedef void               Void;
typedef char    Char;
typedef unsigned long      Bool;
typedef unsigned char      Byte;
typedef unsigned short     Word;
typedef unsigned long      Dword;
typedef unsigned long long Qword;
typedef signed short       Short;
typedef signed long        Int;
typedef signed long long   Long;


//----------------------------------------------------------
// Function Prototypes
//----------------------------------------------------------
extern Dword __stdcall ProcessIncommingData(Void* p);
extern Bool __stdcall  InitBnetSocket();
extern Bool __stdcall  ConnectToBnet();
extern Bool __stdcall  InitBnlsSocket();
extern Bool __stdcall  ConnectToBnls();
[/code]


BnetDiag.cpp
[code]
/*
* BnetDiag.cpp
* ============
* Copyright (C) Matthew J. W.
* All rights reserved.
* Version 1.0
*
*
* Description:
*   Contains all the functionality of the "Battle.net Diagnostic Tool"
*   project.
*
*
************************************************************************************************************************/
#include "BnetDiag.h"
#include <iostream>



////////////////////////////////////////////////////////////
// Sockets
////////////////////////////////////////////////////////////
SOCKET hBnetSocket; // Handle to the socket used for interacting with Battle.net.
SOCKET hBnlsSocket; // Handle to the socket used for interacting with BNLS.


////////////////////////////////////////////////////////////
// Variables
////////////////////////////////////////////////////////////
SOCKADDR_IN BnetSockAddress; // Address of which the BnetSocket will be bound to.
SOCKADDR_IN BnlsSockAddress; // Address of which the BnlsSocket will be bound to.
SOCKADDR_IN BnetHostAddress; // Address of the Battle.net server to connect to.
SOCKADDR_IN BnlsHostAddress; // Address of the BNLS server.
Bool        bThreadIsIdle;
Bool        bSuspendThread;
HANDLE      hWorkerThread;
Byte        SocketBuffer[SOCKET_BUFFER_SIZE];



////////////////////////////////////////////////////////////
// Application Entry Point
////////////////////////////////////////////////////////////

void main()
{
bThreadIsIdle = FALSE;
bSuspendThread = FALSE;


WSAData WSI;
ZeroMemory(&BnetSockAddress, sizeof(SOCKADDR_IN));
ZeroMemory(&BnetHostAddress, sizeof(SOCKADDR_IN));

BnetSockAddress.sin_family = AF_INET;

BnetHostAddress.sin_family = AF_INET;
BnetHostAddress.sin_addr.s_addr = inet_addr("63.240.202.130");
BnetHostAddress.sin_port = htons(6112);

WSAStartup(MAKEWORD(2, 2), &WSI);


struct SID_AUTH_INFO
{
Byte  Header;
Byte  MessageId;
Word  wLength;
Dword dwProtocolId;
Dword dwPlatformId;
Dword dwProductId;
Dword dwVersion;
Dword dwProductLanguage;
Dword dwLocalIp;
Dword dwTimeZoneBias;
Dword dwLocaleId;
Dword dwLanguageId;
Char  strCountryAbbrv[4];
Char  strCountry[10];
} Packet;


Packet.Header            = 0xFF;
Packet.MessageId         = 0x50;
Packet.wLength           = sizeof(SID_AUTH_INFO);
Packet.dwProtocolId      = 0x0;
Packet.dwPlatformId      = '68XI';
Packet.dwProductId       = 'RATS';
Packet.dwVersion         = 0xCD;
Packet.dwProductLanguage = 0;
Packet.dwLocalIp         = inet_addr("192.168.0.2");
Packet.dwTimeZoneBias    = 600;
Packet.dwLocaleId        = 0;
Packet.dwLanguageId      = (Dword) GetUserDefaultLangID();
strcpy(Packet.strCountryAbbrv, "Aus");
strcpy(Packet.strCountry, "Australia");


if(InitBnetSocket())
{
std::cout << "Created Battle.net socket" << std::endl;

if(ConnectToBnet())
{
std::cout << "Connected to Battle.net" << std::endl;

Dword Protocol = 0x01;

std::cout << "Sent: " << send(hBnetSocket, (const char*) &Protocol, sizeof(Dword), NULL) << std::endl;
std::cout << "Sent: " << send(hBnetSocket, (const char*) &Packet, sizeof(SID_AUTH_INFO), NULL) << std::endl;

ProcessIncommingData(NULL);


closesocket(hBnetSocket);
}

else std::cout << "Failed to connect to Battle.net" << std::endl;
}

else std::cout << "Failed to create Battle.net socket.";

WSACleanup();


char x;
std::cin >> x;
}



////////////////////////////////////////////////////////////
// Socket Incomming-Data Processing
////////////////////////////////////////////////////////////

//----------------------------------------------------------
// Dword ProcessIncommingData(Void*)
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Description:
//   Manages data which is sent from the Bnet and Bnls socket's
//   peers.
//
//
// Parameters:
//   [Void*] [p] - Unused.
//
//
// Return:
//   Returns TRUE upon success, elsewise FALSE is returned.
//
//
Dword __stdcall ProcessIncommingData(Void* p)
{
fd_set  BnetSockStatus;
fd_set  BnlsSockStatus;
TIMEVAL Timeout;


//
// Initialize socket status buffers.
//
*BnetSockStatus.fd_array = hBnetSocket;
*BnlsSockStatus.fd_array = hBnlsSocket;


//
// Setup the required timeout construct for use during
// status testing.
//
Timeout.tv_sec  = 0;
Timeout.tv_usec = 0;


//
// Continuously flush the receive buffer of both the Bnet
// and BNLS sockets, and process the received data appropiately.
//
for(;;)
{
//
// Check if we have been asked to suspend execution.
//
if(bSuspendThread)
{
//
// Adjust the appropiate flags.
//
bThreadIsIdle  = TRUE;
bSuspendThread = FALSE;


//
// Suspend the worker thread.
//
SuspendThread(hWorkerThread);


//
// Update socket handles in their associated status buffers,
// incase they've been modified during our suspension.
//
*BnetSockStatus.fd_array = hBnetSocket;
*BnlsSockStatus.fd_array = hBnlsSocket;
}


//
// Reset the BnetSocket's status buffer element count.
//
BnetSockStatus.fd_count = 1;


//
// Test the readability of the BnetSocket.
//
if(select(NULL, &BnetSockStatus, NULL, NULL, (const TIMEVAL*) &Timeout) == 1)
{
//
// Debugging.
//
ZeroMemory(SocketBuffer, 512);

Int iBytes = recv(hBnetSocket, (char*) SocketBuffer, 512, NULL);

std::cout << "Received '" << iBytes << "'." << std::endl;
std::cout << SocketBuffer << std::endl << std::endl;

if(iBytes == 0 || iBytes == -1)
{
std::cout << WSAGetLastError();
break;
}
}


//
// Reset the BnlsSocket's status buffer element count.
//
BnlsSockStatus.fd_count = 1;


//
// Test the readability of the BnlsSocket.
//
if(select(NULL, &BnlsSockStatus, NULL, NULL, (const TIMEVAL*) &Timeout) == 1)
{
//
// Readable.
//
}


//
// Yield execution to the next ready thread, or if that's
// not possible just timeout the current thread for a
// dummy millisecond.
//
if(!SwitchToThread()) Sleep(1);
}


//
// OPERATION FAILURE:
// This point in code should never be reached.
//
return FALSE;
}





////////////////////////////////////////////////////////////
// Battle.net Functions
////////////////////////////////////////////////////////////

//----------------------------------------------------------
// Bool InitBnetSocket()
// =-=-=-=-=-=-=-=-=-=-=-
//
// Description:
//   Creates the BnetSocket, binds it to it's correct address,
//   and places it in asynchronous (non-blocking) mode.
//
//
// Parameters:
//   None.
//
//
// Return:
//   Returns TRUE upon success, elsewise FALSE is returned.
//
//
Bool __stdcall InitBnetSocket()
{
//
// Create a new Window's Socket, the BnetSocket.
//
hBnetSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


//
// Ensure the BnetSocket was created successfully before continuing.
//
if(hBnetSocket != INVALID_SOCKET)
{
//
// Bind the BnetSocket to it's predefined address.
//
if(!bind(hBnetSocket, (const SOCKADDR*) &BnetSockAddress, sizeof(SOCKADDR_IN)))
{
Dword dwAsync = TRUE;


//
// Place the BnetSocket in asynchronous (non-blocking) mode.
//
if(!ioctlsocket(hBnetSocket, FIONBIO, (u_long*) &dwAsync))
{
//
// OPERATION SUCCESS:
//
return TRUE;
}

else
{
//
// ERROR:
//
}
}

else
{
//
// ERROR:
//
}


//
// Close the BnetSocket.
//
closesocket(hBnetSocket);
}

else
{
//
// ERROR:
//
}


//
// OPERATION FAILURE:
//
return FALSE;
}


//----------------------------------------------------------
// Bool ConnectToBnet()
// =-=-=-=-=-=-=-=-=-=-=-
//
// Description:
//   Connects the BnetSocket to the Battle.net server.
//
//
// Parameters:
//   None.
//
//
// Return:
//   Returns TRUE upon success, elsewise FALSE is returned.
//
//
// Remarks:
//   ConnectToBnet functions like a blocking call, and does not
//   return until the final outcome of the connection-attempt
//   is discovered.
//
//
Bool __stdcall ConnectToBnet()
{
//
// Initiate a connection with Battle.net.
//
connect(hBnetSocket, (const SOCKADDR*) &BnetHostAddress, sizeof(SOCKADDR_IN));


//
// Ensure that a connection with Battle.net was intiated
// successfully.
//
// Due to a connection can never be established immediately
// when using non-blocking sockets (As we are); 'connect'
// will always fail with WSAEWOULDBLOCK, this is expected,
// but any other error is a _real_ error.
//
if(WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set  Status;
TIMEVAL Timeout;


//
// Setup the status construct for use in testing the status
// of the BnetSocket.
//
*Status.fd_array = hBnetSocket;


//
// Setup the required timeout construct for use during
// status testing.
//
Timeout.tv_sec  = 0;
Timeout.tv_usec = 0;


//
// Wait to see the outcome of the connection-attempt.
//
for(;;)
{
//
// Reset status element count.
//
Status.fd_count = 1;


//
// Test the BnetSocket for writeability.
//
if(select(NULL, NULL, &Status, NULL, (const TIMEVAL*) &Timeout) == 1)
{
//
// OPERATION SUCCESS:
// A connection has been established with Battle.net.
//
return TRUE;
}


//
// Reset status element count.
//
Status.fd_count = 1;


//
// Test the BnetSocket for errors.
//
if(select(NULL, NULL, NULL, &Status, (const TIMEVAL*) &Timeout) == 1)
{
//
// ERROR:
//


//
// We have failed to connect to Battle.net.
//
break;
}


//
// Yield execution to the next ready thread, or if that's
// not possible just timeout the current thread for a
// dummy millisecond.
//
if(!SwitchToThread()) Sleep(1);
}
}

else
{
//
// ERROR:
//
}


//
// OPERATION FAILURE:
//
return FALSE;
}



////////////////////////////////////////////////////////////
// BNLS Functions
////////////////////////////////////////////////////////////

//----------------------------------------------------------
// Bool InitBnlsSocket()
// =-=-=-=-=-=-=-=-=-=-=-
//
// Description:
//   Creates the BnlsSocket, binds it to it's correct address,
//   and places it in asynchronous (non-blocking) mode.
//
//
// Parameters:
//   None.
//
//
// Return:
//   Returns TRUE upon success, elsewise FALSE is returned.
//
//
Bool __stdcall InitBnlsSocket()
{
//
// Create a new Window's Socket, the BnlsSocket.
//
hBnlsSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


//
// Ensure the BnlsSocket was created successfully before continuing.
//
if(hBnlsSocket != INVALID_SOCKET)
{
//
// Bind the BnlsSocket to it's predefined address.
//
if(!bind(hBnlsSocket, (const SOCKADDR*) &BnlsSockAddress, sizeof(SOCKADDR_IN)))
{
Dword dwAsync = TRUE;


//
// Place the BnlsSocket in asynchronous (non-blocking) mode.
//
if(!ioctlsocket(hBnlsSocket, FIONBIO, (u_long*) &dwAsync))
{
//
// OPERATION SUCCESS:
//
return TRUE;
}

else
{
//
// ERROR:
//
}
}

else
{
//
// ERROR:
//
}


//
// Close the BnlsSocket.
//
closesocket(hBnlsSocket);
}

else
{
//
// ERROR:
//
}


//
// OPERATION FAILURE:
//
return FALSE;
}


//----------------------------------------------------------
// Bool ConnectToBnls()
// =-=-=-=-=-=-=-=-=-=-=-
//
// Description:
//   Connects the BnlsSocket to the Battle.net server.
//
//
// Parameters:
//   None.
//
//
// Return:
//   Returns TRUE upon success, elsewise FALSE is returned.
//
//
// Remarks:
//   ConnectToBnls functions like a blocking call, and does not
//   return until the final outcome of the connection-attempt
//   is discovered.
//
//
Bool __stdcall ConnectToBnls()
{
//
// Initiate a connection with Battle.net.
//
connect(hBnlsSocket, (const SOCKADDR*) &BnlsHostAddress, sizeof(SOCKADDR_IN));


//
// Ensure that a connection with Battle.net was intiated
// successfully.
//
// Due to a connection can never be established immediately
// when using non-blocking sockets (As we are); 'connect'
// will always fail with WSAEWOULDBLOCK, this is expected,
// but any other error is a _real_ error.
//
if(WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set  Status;
TIMEVAL Timeout;


//
// Setup the status construct for use in testing the status
// of the BnlsSocket.
//
*Status.fd_array = hBnlsSocket;


//
// Setup the required timeout construct for use during
// status testing.
//
Timeout.tv_sec  = 0;
Timeout.tv_usec = 0;


//
// Wait to see the outcome of the connection-attempt.
//
for(;;)
{
//
// Reset status element count.
//
Status.fd_count = 1;


//
// Test the BnlsSocket for writeability.
//
if(select(NULL, NULL, &Status, NULL, (const TIMEVAL*) &Timeout) == 1)
{
//
// OPERATION SUCCESS:
// A connection has been established with Battle.net.
//
return TRUE;
}


//
// Reset status element count.
//
Status.fd_count = 1;


//
// Test the BnlsSocket for errors.
//
if(select(NULL, NULL, NULL, &Status, (const TIMEVAL*) &Timeout) == 1)
{
//
// ERROR:
//


//
// We have failed to connect to Battle.net.
//
break;
}


//
// Yield execution to the next ready thread, or if that's
// not possible just timeout the current thread for a
// dummy millisecond.
//
if(!SwitchToThread()) Sleep(1);
}
}

else
{
//
// ERROR:
//
}


//
// OPERATION FAILURE:
//
return FALSE;
}
[/code]
May 27, 2006, 1:38 PM
Kp
Yes, it's a protocol selector.  Useful values are 1 (bncs logon), 2 (bnftp).  3 used to select the chat gateway, but that's been shutdown, so it just sends you a short message and kicks you off.  Some other values have been discovered which don't cause an immediate disconnect, but their purpose is unknown.  There's much speculation about their meaning.

Your definition looks right, but if you're going to be sending packed structures (which gets difficult when you get farther into the protocol and start using multiple variable-length fields, e.g. profile commands), it'd be cleaner to do:[code]struct BNCSHeader {
Byte Header;
Byte MessageId;
Word wLength;
};

struct SID_AUTH_INFO : public BNCSHeader {
/* all the other fields from your struct... */
};
[/code]

The last field is variable length, and holds the full name of your current country.

Note that multi-character constants ('68XI', 'RATS') have a compiler dependent behavior and should be avoided.  Just because Blizzard used them does not mean you should too.

What four bytes do you receive?  I'm guessing it's ff 00 04 00, which is a generic connection probe command that you can safely ignore.

Unless you're targetting Windows 98 systems, it's probably OK to define _WIN32_WINNT to 0x500, so that you can access Windows 2000 features.
May 27, 2006, 4:50 PM
Win32
[quote]
Yes, it's a protocol selector.  Useful values are 1 (bncs logon), 2 (bnftp).  3 used to select the chat gateway, but that's been shutdown, so it just sends you a short message and kicks you off.  Some other values have been discovered which don't cause an immediate disconnect, but their purpose is unknown.  There's much speculation about their meaning.
[/quote]
Ah, cool, thanks for clearing that up.

[quote]
Your definition looks right, but if you're going to be sending packed structures (which gets difficult when you get farther into the protocol and start using multiple variable-length fields, e.g. profile commands), it'd be cleaner to do:
[/quote]
I don't actually plan to use packed structures, I'm just using some very primitive techniques during my testing/debugging stage.

[quote]
The last field is variable length, and holds the full name of your current country.

Note that multi-character constants ('68XI', 'RATS') have a compiler dependent behavior and should be avoided.  Just because Blizzard used them does not mean you should too.

What four bytes do you receive?  I'm guessing it's ff 00 04 00, which is a generic connection probe command that you can safely ignore.

Unless you're targetting Windows 98 systems, it's probably OK to define _WIN32_WINNT to 0x500, so that you can access Windows 2000 features.
[/quote]
Does this mean the country abbreviation field is not interpreted by the BNCS as a null-terminated string? And is simply a static 3 characters?

And yeah, those are the four bytes.

I'm planning to target any OS based at Windows NT.

Thanks for all your help and patience.

Oh, and is there any reason my simple example code doesn't work? (I get disconencted)


-Matt
May 28, 2006, 12:17 AM
Kp
[quote author=Win32 link=topic=15067.msg153280#msg153280 date=1148775440]Does this mean the country abbreviation field is not interpreted by the BNCS as a null-terminated string? And is simply a static 3 characters?

And yeah, those are the four bytes.

I'm planning to target any OS based at Windows NT.[/quote]

Strictly speaking, the last two fields are both variable length.  However, AFAIK, all the country abbreviations are 3 letters, so it's OK to specify that as fixed at 3 characters+null.  The server can tolerate a variable length there (or did a few years ago).

Targetting anything based on NT is a nice goal, but NT4 systems are quite rare these days (even Windows 2000 is largely phased out, aside from corporate markets and Windows geeks who prefer it over Windows XP).
May 28, 2006, 2:42 AM
Win32
[quote]
Strictly speaking, the last two fields are both variable length.  However, AFAIK, all the country abbreviations are 3 letters, so it's OK to specify that as fixed at 3 characters+null.  The server can tolerate a variable length there (or did a few years ago).

Targetting anything based on NT is a nice goal, but NT4 systems are quite rare these days (even Windows 2000 is largely phased out, aside from corporate markets and Windows geeks who prefer it over Windows XP).
[/quote]
Ah alright, that's cleared some things up, thanks.

Would you happen to have any idea why I get disconnected after sending the protocol selector, then 0x50?
The following pseudo-code shows what I'm doing briefly;

[code]
//
// 0x50 message structure.
//
struct SID_AUTH_INFO
{
Byte  Header;
Byte  MessageId;
Word  wLength;

Dword dwProtocolId;
Dword dwPlatformId;
Dword dwProductId;
Dword dwVersion;
Dword dwProductLanguage;
Dword dwLocalIp;
Dword dwTimeZoneBias;
Dword dwLocaleId;
Dword dwLanguageId;
Char  strCountryAbbrv[3];
Char  strCountry[10];
} Packet;


//
// Setup 0x50 construct.
//
ZeroMemory(&Packet, sizeof(SID_AUTH_INFO));

Packet.Header            = 0xFF;
Packet.MessageId         = 0x50;
Packet.wLength           = sizeof(SID_AUTH_INFO);
Packet.dwProtocolId      = 0x0;
Packet.dwPlatformId      = '68XI';
Packet.dwProductId       = 'RATS';
Packet.dwVersion         = 0xCD;
Packet.dwProductLanguage = 0;
Packet.dwLocalIp         = inet_addr("192.168.0.2");
Packet.dwTimeZoneBias    = 600;
Packet.dwLocaleId        = 0;
Packet.dwLanguageId      = (Dword) GetUserDefaultLangID();
strcpy(Packet.strCountryAbbrv, "Aus");
strcpy(Packet.strCountry, "Australia");


//
// Send protocol selector to Battle.net.
//
Dword dwProtocol = 1;
send(sock, (const char*) &dwProtocol, sizeof(Dword), NULL);


//
// Send 0x50
//
send(sock, (const char*) &Packet, sizeof(SID_AUTH_INFO), NULL);
[/code]

The only response I ever get is a connection-closure, or, if I only send the protocol selector I receive those 4 obsecure bytes after quite some time has elapsed.


-Matt
May 28, 2006, 3:30 AM
FrOzeN
This is just a guess, (as I don't know C++) but "Australia" is only 9 characters and you've assigned 10 for it. Could it be sending "Australia" with an extra space making it invalid?
May 28, 2006, 3:39 AM
Win32
[quote]
This is just a guess, (as I don't know C++) but "Australia" is only 9 characters and you've assigned 10 for it. Could it be sending "Australia" with an extra space making it invalid?
[/quote]
I was under the presumption it needed to be null-terminated, due to the varying lengths of country names.


-Matt
May 28, 2006, 3:42 AM
FrOzeN
Yeah it does. I didn't understand you're code. Also, in that case the abbreviation has to be Null Terminated aswell (despite it always being 3 characters).
May 28, 2006, 3:44 AM
Win32
[quote]
Yeah it does. I didn't understand you're code. Also, in that case the abbreviation has to be Null Terminated aswell (despite it always being 3 characters).
[/quote]
I initially had it as being null-terminated, but currently it does not make any difference in that I'm still being disconnected no matter which way I go.


-Matt
May 28, 2006, 3:46 AM
Win32
Hmm, I think I've resolved the problem. VC++ was specified to automatically align constructs.
Thanks for all your help guys.


-Matt
May 28, 2006, 4:50 AM
rabbit
[quote author=Kp link=topic=15067.msg153294#msg153294 date=1148784123]
[quote author=Win32 link=topic=15067.msg153280#msg153280 date=1148775440]Does this mean the country abbreviation field is not interpreted by the BNCS as a null-terminated string? And is simply a static 3 characters?

And yeah, those are the four bytes.

I'm planning to target any OS based at Windows NT.[/quote]

Strictly speaking, the last two fields are both variable length.  However, AFAIK, all the country abbreviations are 3 letters, so it's OK to specify that as fixed at 3 characters+null.  The server can tolerate a variable length there (or did a few years ago).
[/quote]Really?  IT, DE, JP, UK, IR..so many are 2, or am I missing something?  I know USA and CAN, but I've seen a lot of others...
May 28, 2006, 2:09 PM
Yegg
[quote author=rabbit link=topic=15067.msg153322#msg153322 date=1148825392]
[quote author=Kp link=topic=15067.msg153294#msg153294 date=1148784123]
[quote author=Win32 link=topic=15067.msg153280#msg153280 date=1148775440]Does this mean the country abbreviation field is not interpreted by the BNCS as a null-terminated string? And is simply a static 3 characters?

And yeah, those are the four bytes.

I'm planning to target any OS based at Windows NT.[/quote]

Strictly speaking, the last two fields are both variable length.  However, AFAIK, all the country abbreviations are 3 letters, so it's OK to specify that as fixed at 3 characters+null.  The server can tolerate a variable length there (or did a few years ago).
[/quote]Really?  IT, DE, JP, UK, IR..so many are 2, or am I missing something?  I know USA and CAN, but I've seen a lot of others...
[/quote]

This isn't the most useful post, but I remember seeing a "SPA" (Spanish). I've never seen one with two characters.
May 28, 2006, 4:44 PM
UserLoser
[quote author=Win32 link=topic=15067.msg153297#msg153297 date=1148787012]
[quote]
Strictly speaking, the last two fields are both variable length.  However, AFAIK, all the country abbreviations are 3 letters, so it's OK to specify that as fixed at 3 characters+null.  The server can tolerate a variable length there (or did a few years ago).

Targetting anything based on NT is a nice goal, but NT4 systems are quite rare these days (even Windows 2000 is largely phased out, aside from corporate markets and Windows geeks who prefer it over Windows XP).
[/quote]
Ah alright, that's cleared some things up, thanks.

Would you happen to have any idea why I get disconnected after sending the protocol selector, then 0x50?
The following pseudo-code shows what I'm doing briefly;

[code]
//
// 0x50 message structure.
//
struct SID_AUTH_INFO
{
Byte  Header;
Byte  MessageId;
Word  wLength;

Dword dwProtocolId;
Dword dwPlatformId;
Dword dwProductId;
Dword dwVersion;
Dword dwProductLanguage;
Dword dwLocalIp;
Dword dwTimeZoneBias;
Dword dwLocaleId;
Dword dwLanguageId;
Char  strCountryAbbrv[3];
Char  strCountry[10];
} Packet;


//
// Setup 0x50 construct.
//
ZeroMemory(&Packet, sizeof(SID_AUTH_INFO));

Packet.Header            = 0xFF;
Packet.MessageId         = 0x50;
Packet.wLength           = sizeof(SID_AUTH_INFO);
Packet.dwProtocolId      = 0x0;
Packet.dwPlatformId      = '68XI';
Packet.dwProductId       = 'RATS';
Packet.dwVersion         = 0xCD;
Packet.dwProductLanguage = 0;
Packet.dwLocalIp         = inet_addr("192.168.0.2");
Packet.dwTimeZoneBias    = 600;
Packet.dwLocaleId        = 0;
Packet.dwLanguageId      = (Dword) GetUserDefaultLangID();
strcpy(Packet.strCountryAbbrv, "Aus");
strcpy(Packet.strCountry, "Australia");


//
// Send protocol selector to Battle.net.
//
Dword dwProtocol = 1;
send(sock, (const char*) &dwProtocol, sizeof(Dword), NULL);


//
// Send 0x50
//
send(sock, (const char*) &Packet, sizeof(SID_AUTH_INFO), NULL);
[/code]

The only response I ever get is a connection-closure, or, if I only send the protocol selector I receive those 4 obsecure bytes after quite some time has elapsed.


-Matt
[/quote]

[code]
strcpy(Packet.strCountryAbbrv, "Aus\0");
strcpy(Packet.strCountry, "Australia\0");

Byte Protocol = 1;
send(sock, (const char*)Protocol, 1, 0);
[/code]

Try that, also supply packet capture.  Who knows what exacty sizeof is returning.  All I know, it's most likely a bad idea using sizeof to specify length when there are variable length strings in the message
May 28, 2006, 7:22 PM
FrOzeN
[quote author=rabbit link=topic=15067.msg153322#msg153322 date=1148825392]
[quote author=Kp link=topic=15067.msg153294#msg153294 date=1148784123]
[quote author=Win32 link=topic=15067.msg153280#msg153280 date=1148775440]Does this mean the country abbreviation field is not interpreted by the BNCS as a null-terminated string? And is simply a static 3 characters?

And yeah, those are the four bytes.

I'm planning to target any OS based at Windows NT.[/quote]

Strictly speaking, the last two fields are both variable length.  However, AFAIK, all the country abbreviations are 3 letters, so it's OK to specify that as fixed at 3 characters+null.  The server can tolerate a variable length there (or did a few years ago).
[/quote]Really?  IT, DE, JP, UK, IR..so many are 2, or am I missing something?  I know USA and CAN, but I've seen a lot of others...
[/quote]
All countries have codes representing them in both 2 and 3 letter abbreviations. Though, Battle.net requests the 3 character country code. Eg, you said "JP"; Battle.net wants "JPN".

Preferably, it's best just to collect the information with the GetLocaleInfo() API.
May 29, 2006, 1:45 AM
JoeTheOdd
As for UK, It's GBR, I believe.
May 29, 2006, 4:18 PM
shout
[quote author=Win32 link=topic=15067.msg153297#msg153297 date=1148787012]
[code]
Packet.dwPlatformId      = '68XI';
Packet.dwProductId      = 'RATS';
[/code]
[/quote]
Should be:
[code]
Packet.dwPlatformId      = 'IX86';
Packet.dwProductId      = 'STAR';
[/code]

[Could be wrong]
Multi character literals are reversed by the compiler/preprocessor.
[/Could be wrong]
May 29, 2006, 4:56 PM
Myndfyr
It's the compiler.
May 29, 2006, 7:25 PM
Win32
[quote]
Try that, also supply packet capture.  Who knows what exacty sizeof is returning.  All I know, it's most likely a bad idea using sizeof to specify length when there are variable length strings in the message
[/quote]
Well, the character arrays are of a static length, and I always make sure that 'sizeof' returns the proper length. But thanks for the advice anyway.


-Matt
May 29, 2006, 11:58 PM

Search