StarCraft II Battle.net Wire Protocol Reference

Purpose. This is a standalone wire reference for the current StarCraft II Battle.net path. It begins with the generic protobuf control connection, follows the handoff into SC2's native service connection, and documents the bit-packed records used there. Live observations and build constants target macOS Base97563. Native type names and logical schemas are taken from a build-97364 metadata snapshot; layouts marked live verified have also been reconstructed against Base97563 traffic. Private account data, credentials, session secrets, endpoints, and message contents are intentionally omitted.

1. Names and protocol layers

StarCraft II's online path is a stack, not one protocol. This document uses the following names consistently:

Name used hereMeaning
Battle.net platformThe complete account, routing, session, and game-service system sometimes called Battle.net 2.0.
BGSBattle.net Game Services, the generic protobuf RPC control plane carried here in WebSocket binary messages inside TLS.
FrontSC2's name for its regional BGS connection. It authenticates the account and obtains the game-native handoff.
Web challengeThe HTTPS account-login step requested by BGS. It returns a short-lived credential to the client.
GameUtilities handoffThe BGS RPC that returns the native endpoint, session material, identity data, and native logon response.
SunkenSC2's name for the game-native service connection reached after Front.
BSNThis reference's short name for SC2's native bit-packed service protocol, generated by the bsnc toolchain.
BSN metadataThe build-time type library embedded in SC2. Numeric type IDs resolve to structural records and optional human-readable names; the library itself is not sent on the wire.
Naming note. “BGS,” “Front,” and “Sunken” come from Blizzard service and client terminology. “BSN” is only a compact label used by this reference; no expanded form is implied.

With these names established, the next chapter follows one session from the first Front connection through the Sunken service stream.

Back to contents

2. High-level architecture and flow

SC2 signs in on Battle.net's shared BGS service, then moves the authorized session to SC2's native service. The first connection establishes who you are and which game account may log in; the second proves that it received that authorization and carries the live SC2 services. The protocol calls that continuation Resume.

  1. Open the Battle.net control connection

    The client connects to the regional Front endpoint. TLS protects the socket, WebSocket supplies message boundaries, and BGS protobuf RPC carries connection and account operations.

    TCP/1119 → TLS → WebSocket → BGS

  2. Authenticate the Battle.net account

    BGS accepts a cached credential or asks the client to complete an HTTPS account challenge. Successful logon returns the available SC2 game accounts and a BGS session key.

    BGS Logon → optional web challenge → LogonResult

  3. Authorize SC2 and obtain the native handoff

    The client selects an SC2 game account and calls GameUtilities.ProcessClientRequest. Its response supplies the private material needed to continue on SC2's native service plane.

    Native endpointwhere Sunken accepts the second connection
    64-byte session seedinput to the Resume proof and transport keys
    LogonResponse3identity, region, and native bootstrap values
  4. Open a new connection and resume the authorized context

    The client opens a separate TCP connection to Sunken and sends Auth/1 ResumeRequest. The Auth proof exchange demonstrates possession of the handoff seed and binds the new socket to the account and game account authorized on Front.

    The TCP connection changes here. Authorization continues; the Front socket itself does not.

    new TCP/1119 → plaintext BSN Auth → Resume proof

  5. Enable stream protection and run SC2 services

    After the server proof succeeds, Conn/5 EnableEncryption switches both directions to independent RC4 states. The same BSN stream then carries connection bootstrap, identity, presence, friends, channels, chat, parties, and game services.

    RC4-protected BSN → service registry → routed records

The next chapter begins with the outer BGS control plane: its framing, dispatch rules, account logon, and the GameUtilities request that creates the handoff.

Back to contents

3. BGS protobuf RPC

BGS is the generic Battle.net Game Service control plane used before SC2 enters its native service stream. SC2 embeds a standard protobuf descriptor set for connection, authentication, challenge, session, GameUtilities, account, channel, presence, and related services.

3.1 WebSocket transport and RPC frame

The Base97563 client first establishes TLS to the regional Front endpoint, then performs an RFC 6455 upgrade with subprotocol v1.rpc.battle.net. Each binary WebSocket message contains exactly one BGS RPC frame. WebSocket therefore supplies the outer message and body boundary; the two-byte BGS prefix below measures only the protobuf header.

2 bytes
header length
uint16_be
header_length bytes
bgs.protocol.Header
remaining message bytes
protobuf body; may be empty

The length prefix covers only the protobuf header. When Header.size is present it must agree with the remaining WebSocket-message length; Base97563 requests can omit it.

offset  size                 description
------  -------------------  ----------------------------------------------
0       2                    header length, unsigned big-endian
2       header_length        protobuf bgs.protocol.Header
...     remainder of message protobuf request/response body

uint16_be header_length
bytes     header[header_length]
bytes     body[websocket_message_end - current_offset]

Header.size is a body-length assertion when present, not the outer message delimiter on this path. The two-byte prefix measures only the encoded protobuf header, not the complete RPC frame or WebSocket message.

Client-to-server WebSocket messages set the RFC 6455 mask bit. The current macOS client uses an all-zero four-byte mask, so the payload bytes remain visibly unchanged even though the frame is formally masked. Server messages are unmasked.

Header fieldProtobuf wire typeMeaning
1 service_idvarintNumeric dispatch value. The first Connect uses 0; responses use 0xfe.
2 method_idvarintMethod number within the selected service.
3 tokenvarintRequest/callback correlation token.
4 object_idvarintOptional addressed service object.
5 sizevarintBody byte count.
6 statusvarintRPC result/status code.
7 errorlength-delimited, repeatedStructured error details.
8 timeoutvarintOptional request timeout.
9 is_responsevarint booleanExplicit response marker when present.
11 service_hashfixed32FNV-1a hash of the full protobuf service name. Protobuf fixed32 is little-endian on the wire.
13 client_idlength-delimited UTF-8Optional client identifier.

3.2 Dispatch and callbacks

A BGS header answers two separate questions: which operation should receive this body? and which earlier call does this reply belong to? Service and method fields perform dispatch; the token performs correlation.

Connection bootstrap The first ConnectionService.Connect is the exception: service_id=0, method_id=1, token=0.
Client call
Request headerservice_hash
method_id
token = t
Server dispatchhash selects service
method selects operation
Response headerservice_id=0xfe
token = t
status
Server callback
Callback headerlistener service_hash
method_id
token = c
Client dispatchdecode listener body
run callback
Declared resultreply with token c
or send nothing for
NO_RESPONSE

Tokens correlate calls; they do not serialize traffic. Callbacks and connection-control messages may arrive while an unrelated request remains pending, so dispatch must examine every complete BGS header.

After the special first Connect, client requests identify a service with the 32-bit FNV-1a hash of its full protobuf name:

h = 0x811c9dc5
for each UTF-8 byte b in full_service_name:
    h = h XOR b
    h = (h * 0x01000193) AND 0xffffffff

Relevant names include:

Server-to-client calls use listener services. If the descriptor declares an ordinary response, answer with a header whose service_id is 0xfe, whose token is the callback token, and whose status is zero. If the declared return type is NO_RESPONSE, send nothing. An empty response is not equivalent to no response.

Connection-control calls and listener callbacks can arrive while another token remains pending. Decode and dispatch each message by its own header, acknowledge it when its declared result requires one, and continue waiting for unrelated tokens.

3.3 Logon sequence

StepDirectionService / methodNotes
1C→SConnectionService / 1Special service_id=0, token=0; advertises bindless RPC.
2C→SAuthenticationServer / 1Logon: program S2, platform Mc64, locale enUS, embedded BGS SDK identity, application_version=0, and optionally cached web credentials.
3S→CChallengeNotify / 3Conditional external challenge with payload type web_auth_url. Declared NO_RESPONSE; omitted when cached credentials are accepted.
4local HTTPSBattle.net account flowWhen challenged, cookies, MFA, CAPTCHA, and account state stay in the web view.
5C→SAuthenticationServer / 7When challenged, submits the short-lived credential returned by the web flow.
6S→CAuthenticationClient / 5LogonResult: account, game accounts, region, and 64-byte session key.
7C→SAuthenticationServer / 8After successful authentication, generates a successor cached credential for a later Logon; this also rotates a credential that was just accepted.
8C→SGameUtilities / 1SC2 Front bootstrap. On this path it follows logon directly, without an intervening SessionService call.

For Base97563, LogonRequest.version is the embedded SDK identity Battle.net Game Service SDK v1.48.2 "cf68e241e0"/104, while protobuf field 6 application_version is zero. These fields must not be inferred from the installation build number.

Authentication listener traffic can be interleaved with the ordinary RPC responses: method 10 reports a logon update, method 14 reports game-account selection, and methods 11–13 are declared NO_RESPONSE. Dispatch them as callbacks rather than mistaking them for whichever request token is pending.

The browser or embedded web view handles only the account challenge. The BGS connection remains the protocol client: after the web flow returns its short-lived credential, the client submits that value with AuthenticationServer method 7.

The cached credential is distinct from the one-time credential returned by the web challenge. It is opaque, can suppress the next browser challenge, and should be replaced after a successful use. Rejection simply returns the flow to the ordinary web challenge.

3.4 GameUtilities Front request

Front sends GameUtilities.ProcessClientRequest method 1 with a deliberately sparse ClientRequest. Top-level field 1 repeats typed attributes; top-level field 4 is the selected SC2 game-account entity. Fields for host process, Battle.net account, program, and client info are absent on this path.

Attribute nameVariant typeCurrent value shape
LogonTokenRequeststring"0.0.1"
environmentstringRegional environment string; "US" for this target.
session_keyblob64 private bytes from LogonResult.
localestring"enUS"

An Attribute is protobuf field 1 name plus field 2 Variant. Known Variant arms are field 2 bool, 3 signed integer, 4 double, 5 string, 6 blob, 7 embedded message, 8 FourCC string, 9 unsigned integer, and 10 entity ID.

A successful response is another attribute bag. The handoff requires:

These response attributes are the boundary between the generic BGS control plane and SC2's native protocol. The next chapter explains how they are used to open the Sunken connection.

Back to contents

4. Front-to-Sunken handoff

The SC2 client names the generic BGS side “Front” and the native endpoint “Sunken.” Front authenticates the Battle.net account, selects an SC2 game account, and returns the values needed to open and authenticate the second connection.

The logon_response attribute is not an opaque ticket. It decodes as Battlenet::Client::Authentication::LogonResponse3, including response status, final authentication-module requests, ping timeout, regulator rules, account and game-account region, game-account name, failure count, and optional RAF state. The enclosing protobuf blob carries no native bit count; unused bits in the last byte must be zero.

The native TCP connection may be established before Front finishes closing, but the first native Auth/1 ResumeRequest is written after the Front shutdown. The sockets remain independent even when their lifetimes briefly overlap.

An ordered Front shutdown uses ConnectionService.RequestDisconnect (method 7, declared NO_RESPONSE). The server answers with the one-way ConnectionService.ForceDisconnect notification (method 4) and then closes TLS. This notification is a protocol event, not the response frame that NO_RESPONSE explicitly forbids.

From this point onward, the transport and payload format are native BSN. The next chapter introduces its bit cursor, record header, and schema-delimited boundaries before any authentication payloads are decoded.

Back to contents

5. Native BSN record stream

“BSN” is used here for the native bit-packed service protocol generated by Blizzard's embedded bsnc toolchain. Unlike the preceding BGS connection, native records are schema-delimited bitstreams rather than protobuf messages inside WebSocket boundaries.

5.1 The bitstream from first principles

A BSN record is not a list of byte-sized packet fields. It is a sequence of fields packed back-to-back into an array of bytes. Each field declares exactly how many bits it consumes, and the next field begins wherever the previous one stopped—even if that position is halfway through a byte.

One byte has eight numbered positions.

A hex viewer conventionally draws the most-significant position first, so its columns run from bit 7 down to bit 0.

hex-display order
76543210
cursor order
01234567

A decoder owns one position: (byte index, bit index). Reading a field consumes its declared number of bits and advances that position. Reaching bit 7 does not end the field; the cursor wraps to bit 0 of the next byte and keeps going.

The first sixteen cursor positions of a BSN record

This view is deliberately arranged in cursor order, so read it left to right. Hover or focus a field to follow what it consumes.

byte 0first 8 cursor positions
byte 1next 8 cursor positions
11 header bits6 command + 1 flag + 4 slot payload bitsbegin at absolute cursor position 11

The byte boundary is only a storage boundary. It does not align fields. Here the four-bit slot begins in the final position of byte 0, continues through the first three positions of byte 1, and leaves the cursor at byte 1, bit 3 for the payload.

Command consumes positions 0–5. It fits inside byte 0, so the cursor simply advances six positions and stops at byte 0, bit 6.

The flag consumes position 6. After this one-bit field, only byte 0 bit 7 remains available.

Slot is one field, drawn in two pieces. Its declared width is four bits. One bit fits before the boundary and three bits continue in byte 1. Both green regions belong to the same value.

Payload begins at absolute position 11. That is byte 1, bit 3—not the start of a new byte. Payload fields continue from this exact cursor position until the selected schema is complete.

How a number is split when it crosses a byte

Cursor movement explains where a field is stored. Integer chunking is a second rule that explains which part of the value goes into each region. If an integer does not fit before the next byte boundary, its most-significant chunk goes into the remaining space and its lower bits continue in the next byte. The boundary splits the value; it does not reverse it.

field service slot value 14 = 1110₂ starting position byte 0, bit 7

Bytes below use the conventional display order bit 7 → bit 0. The BSN cursor moves in the opposite visual direction: it begins at bit 0, advances toward bit 7, then wraps to bit 0 of the next byte.

byte 011000000₂ = c0₁₆
byte 1ppppp110₂
  1. 1command
  2. 2has-service flag
  3. 3slot 1 + 110
  4. 4payload

Hover or focus a colored field. The step numbers show cursor order. The diagram itself keeps the conventional byte display order so the resulting bytes remain recognizable in a hex dump.

Command is read first. Six bits fit entirely in byte 0, occupying its low positions 0 through 5. This example uses command 0 only to keep those bits visually quiet.

The one-bit flag follows. It occupies byte 0 bit 6 and leaves exactly one bit available in that byte.

The four-bit slot must split. Its binary value is 1110₂. The one available position receives the value's high bit, 1. The remaining low value, 110₂, continues in byte 1 bits 2 through 0. Reading the two chunks as 1 || 110 reconstructs 1110₂ = 14.

The next field starts immediately. After the slot consumes byte 1 bits 0 through 2, the payload begins at bit 3. The letters p are payload bits, not zero padding.

The decoder below expresses the same rule. The important operation is value = (value << take) | chunk: each earlier wire chunk becomes the more-significant part of the reconstructed integer.

read(width):
    value = 0
    while width remains:
        take = min(width, bits_left_in_current_byte)
        chunk = (current_byte >> current_bit_offset) & ((1 << take) - 1)
        value = (value << take) | chunk
        advance(take)

Consequently, a field cannot be cut out of the byte stream and decoded as an ordinary standalone integer. Its interpretation depends on the bit position at which the field began. Keep one cursor for the complete record, including its routing header.

5.2 Routing header

command_id       6 bits   0..63
service_present  1 bit    0 = no service slot follows
service_slot     4 bits   present only when service_present = 1

total: 7 bits without a slot, 11 bits with a slot
6 bitscommand
1 bithas service
4 bitsservice slot
if present
variable bitspayload selected by route schema
0..7 bitszero pad

Hover or focus a field to isolate it. There is no outer record length: the route selects the payload schema, and that schema determines where the record ends. Section 5.3 follows that process.

Command, 6 bits. A number from 0 through 63. Its meaning is local to the selected service and may also depend on direction; command 11 in Chat is unrelated to command 11 in Connection.

Has-service flag, 1 bit. If set, a four-bit service slot follows. If clear, the header ends here and the payload begins at bit 7 of the first byte.

Service slot, 4 bits when present. This session-local number resolves through the runtime registry to a service such as Auth, Conn, or Chat. It is not a chat-room index.

Payload, schema-sized. The tuple of direction, service, and command selects its decoder. Because there is no generic length prefix, the decoder must consume exactly the right number of bits.

Final padding, 0 through 7 zero bits. Padding ends the record on a byte boundary so the next routing header starts at the beginning of the next byte.

With a service slot, the payload begins three bits into the second byte; the upper five bits of that byte already belong to the payload. Without a service slot, the payload begins at bit 7 of the first byte.

for a route with a service slot
byte0 = (command & 0x3f) | 0x40 | (((slot >> 3) & 1) << 7)
byte1 bits 0..2 = slot & 0x07

worked arithmetic only: command 11, slot 5
byte0 = 0x4b
byte1 bits 0..2 = 0x05

The worked slot is arbitrary. Service slots are assigned for a connection; only the service FourCC and command meaning are stable.

5.3 How record length is determined

BSN records are schema-delimited. There is no universal field saying “this record is N bytes long.” Instead, the route identifies a payload decoder, and that decoder advances the shared bit cursor until its top-level value is complete. The cursor position at that moment is the logical end of the record.

Concrete example: a server-to-client Chat/11 MessageRecv record. The values are omitted; only the decoder’s consumed-bit counts are shown.

11 header+336 payload+5 pad=352 bits=44 bytes

The length is a result, not an input. The decoder learns the route, executes that route’s payload schema, rounds its final bit position up to a byte boundary, and only then knows how many bytes belong to the record.

The route is the only universal prefix. It consumes 7 or 11 bits and identifies the command plus an optional runtime service slot. It contains no payload-size or record-size field.

The route chooses the decoder. Direction, resolved service FourCC, and command identify the payload type and generated field order. Looking up the decoder consumes no additional wire bits.

The payload decoder advances the shared cursor. Fixed-width members, local counts, option flags, choice selectors, and nested members collectively determine when the top-level value is complete.

Final padding is deterministic. Once the top-level payload ends at bit 347, five zero bits reach bit 352, the next byte boundary. Non-zero final padding indicates a wrong schema or a corrupted stream.

The buffer can now release 44 bytes. The next byte begins another routing header. TCP may have delivered less than, exactly, or more than those 44 bytes in any particular read.

What makes a payload’s extent deterministic?

Fixed-width valueThe schema supplies the exact width: for example, one bit for a Boolean or 32 bits for a FourCC.
Array or byte stringA bounded local count is decoded first. It determines the number of elements or raw bytes that follow.
Optional valueOne presence bit decides whether the nested value follows.
ChoiceA bounded selector chooses one arm; only that arm is decoded.
StructureMembers are decoded recursively in generated wire order until the structure is complete.
Alignment pointStrings and blobs may advance to the next byte before their raw bytes; final record padding does the same after the top-level value.

Local counts are not record lengths. An array count describes one array; a string length describes one string; an optional flag and choice selector control only their nested values. The enclosing schema combines all of those decisions recursively to determine the payload’s total extent.

Counts use the same bounded-integer machinery as other ranged values. For a declared range [minimum..maximum], the metadata supplies the encoded bit width and the wire stores value - minimum. Thus an array declared [1..64] can store count - 1 in six bits. A fixed range, where minimum equals maximum, consumes no count bits at all.

The general calculation is:

logical_bits = routing_header_bits + payload_bits_consumed_by_schema
padding_bits = (-logical_bits) & 7
record_bytes = (logical_bits + padding_bits) / 8

An incremental socket decoder therefore does not wait for a declared record size. It tries to execute the selected schema against the bytes currently buffered. If a field is incomplete, it reads more TCP data and resumes. Once the schema finishes, it validates the final zero padding, removes exactly that many bytes, and starts the next routing header at the next byte.

Parser procedure

1. Read the 7- or 11-bit routing header.
2. Resolve (direction, service slot, command) to a payload type and generated order.
3. Decode fields until that schema is complete.
4. Consume zero padding through the next byte boundary.
5. The next byte begins the next routing header.
Consequence for unknown routes. Without the selected payload schema, a decoder generally cannot calculate the record boundary or skip safely to the next record. A wrong field order has the same effect: it changes the cursor position and causes later records to be interpreted at the wrong byte. TCP packet boundaries cannot be used to recover alignment.

Internal alignment is also relative to the complete record. Strings, byte strings, and blobs can align the cursor before their raw bytes, so encoding a payload at bit zero and prepending a separately encoded route header produces a different layout. The next chapter resolves the numeric service slot into a stable FourCC; Section 7 then explains how the selected payload type is described.

Back to contents

6. Runtime service registry

The routing header has room for a four-bit service slot, so one connection can address at most sixteen native services. The slot is an index into that connection's registry; the registry entry supplies a stable FourCC and its command-handler table.

Record header direction S→C
command 11
slot s
Connection registry registry[s] = Chat
Stable route identity (S→C, Chat, 11)
Endpoint MessageRecv
payload decoder

The example uses symbolic slot s deliberately. Store the connection's slot-to-FourCC mapping, then identify records by direction, FourCC, and command. A hard-coded numeric slot is not a portable route name.

The complete route identity is (direction, service FourCC, command). The numeric slot is session state, not protocol identity. A decoder should resolve the slot first and use the resulting FourCC for every later lookup.

6.1 Assignments used by the documented build

Base97563 traffic uses the assignments below. They make a captured route such as slot 5, command 11 readable as Chat/11. Keep the FourCC in decoded output: a slot number is only the compact address used by this build's native connection and should not be treated as a permanent service ID.

SlotServiceRoutes confirmed in this reference
0Auth0, 1, 2, 17, 18
1Conn1, 3, 5, 10, 11, 13, 14
3Frnd30, 31, 33
4Pres0, 1
5Chat0, 1, 2, 11, 21, 22, 25, 26, 27, 32, 33
10S2Ms27
11Cach9
13S2Mp57
14Prfl4
15Toon0, 5, 6, 10, 14

Connection core

Auth authenticates the native session. Conn controls the transport, reports failures, and carries generic routed envelopes.

Identity and social

Toon, Pres, Frnd, Chat, and Prfl cover playable identity, presence, friends, channels, messages, and profile settings.

Game and shared data

S2Ms, S2Mp, Cach, Ladd, Achv, Prty, and Supp cover SC2 master data, multiplayer, caches, ladder, achievements, parties, and support operations.

Resolving the service still does not reveal the payload fields. The next chapter explains the embedded type library that associates a routed endpoint with a recursive BSN schema.

Back to contents

7. Embedded BSN schema metadata

The previous chapter established that a BSN route selects the schema which determines where its payload ends. That raises the next question: where does that schema come from?

SC2 ships a compact, version-7 type library produced by Blizzard's bsnc toolchain. It is embedded in the client executable alongside the generated encoders and decoders. It is not transmitted in each record, and it is separate from the protobuf descriptors used by BGS.

7.1 From a route to a schema

Each metadata type has a build-specific numeric ID. Looking up that ID yields a structural record and, when reflection names were retained, a naming record. Structural records refer to other type IDs, so resolving one top-level payload produces a graph rather than a flat field list.

The payload structures in this document are a human-readable rendering of that decoded type graph. They are documentation notation, not a language carried on the wire. For example:

illustrative rendering of decoded metadata
Authentication::ProofRequest {
    request  ModuleInput[0..4]
}

ModuleInput {
    id    blob[40]
    data  blob[0..1023]
}

Here the array bound, blob bounds, nested type relationship, type name, and member names all come from metadata. The braces and formatting are ours.

7.2 Native type vocabulary

The low six bits of a structural record identify one of sixteen kinds. The kind determines what other information the record carries and what the value consumes from the BSN bitstream.

Scalar values

5 Boolean
One bit.
7 enum
A bounded integer, optionally restricted to listed values.
8 FourCC
Exactly 32 bits.
9 integer
A bounded, fixed-width integer.
10 void
No bits.
12 float32
32 raw bits.
13 float64
64 raw bits.

Containers

1 array
Bounded count, then repeated elements of another type.
2 byte string
Bounded count, byte alignment, then raw bytes.
3 bit array
Bounded bit count, then packed bits.
4 blob
Bounded count, byte alignment, then raw bytes.
11 optional
One presence bit, then the contained value when present.
15 UTF-8 string
Bounded byte count, alignment, then UTF-8 bytes.

Composition

6 choice
A bounded selector followed by the selected arm.
14 struct
A sequence of named or unnamed member types.
16 alias
A transparent reference to another type.

Most bounded values encode value - minimum using the recorded bit width. Fixed-size forms can omit the count entirely. For indexed choices, enums, and structs, bit 7 can mean that indices are the full contiguous range rather than an explicit list.

7.3 How the type library is stored

This binary layout matters when extracting the type library from an SC2 build. A packet decoder which has already loaded the parsed type graph does not encounter this header or these tables on the network.

Type ID n indexes element n in both offset tables. Its shape offset points to the structural record. Its name offset points to a small record of 32-bit offsets into the NUL-terminated UTF-8 string pool, or is zero when no names were retained. The header's type_count, dump_size, and string_size delimit the five regions.

MetadataHeader  # five unsigned big-endian u32 values
    version             # currently 7
    flags
    type_count
    dump_size
    string_size

followed by
    dump_offset[type_count]
    dump_data[dump_size]
    string_record_offset[type_count]
    string_data[string_size]

The first byte of each structural record begins with:

bits 0..5  kind tag (1..16)
bit  6     obfuscated flag
bit  7     kind-specific compact-form flag

Bit 7 is interpreted by the selected kind; for example, it can indicate an implicit contiguous index range instead of an explicit list.

The registry and type library now provide everything needed to parse native records. The next chapter applies them to the first Sunken exchange: Resume authentication and the transition to protected service traffic.

Back to contents

8. Native Resume authentication

The Resume path starts immediately after the Front handoff. The Sunken endpoint does not greet first; it waits for client Auth/1.

8.1 Where the name “Resume” comes from

Resume is Blizzard’s type name. SC2’s embedded BSN metadata contains the fully qualified types Battlenet::Client::Authentication::ResumeRequest and Battlenet::Client::Authentication::ResumeResponse. The runtime Auth route maps client-to-server Auth/1 to the request and server-to-client Auth/1 to the response. This chapter uses those embedded names throughout.

What is resumed is the authenticated session context. Front has already authenticated the Battle.net account, selected an SC2 game account, and obtained the native endpoint plus session material from GameUtilities. The new Sunken connection uses ResumeRequest and its proof exchange to demonstrate possession of that handed-off state and continue it on the native service plane. In other words, authorization crosses from one protocol connection to another.

Native authentication entry points named in the embedded metadata
RouteEmbedded request typeStarting context
Auth/0LogonRequest3Cold native account logon; asks the native service to choose account-logon modules.
Auth/1ResumeRequestContinues the account and game-account session authorized by the Front handoff. This is the path documented here.
Auth/17SingleSignOnRequest3Begins from a native SSO identifier supplied by another trusted context.
Resume does not mean reconnecting the TCP socket. Sunken is a new TCP connection. The term also does not promise restoration of a previous chat roster, game, or disconnected native session. It names the authentication entry point that continues Front-authorized identity and key material on that new connection.

8.2 Auth/1 ResumeRequest

Logical payload:

RequestCommon:
    m_program   = FourCC("S2")
    m_platform  = FourCC("Mc64")
    m_locale    = FourCC("enUS")
    m_versions  = five Version records (table below)
m_account            = private account-login bytes
m_gameAccountRegion  = u8 region from Front LogonResponse3
m_gameAccountName    = private game-account bytes
ProgramComponent/platformVersion
S2NGD10x5bc8dcc1
S2NGD20xfade3a32
S2NGD30x0c129365
S2NGD40x86b7c0ed
BnetMc640x000a16a7 (661159)

These are Base97563-specific values. The final native compatibility number is not the installation build number, and the outer BGS LogonRequest independently sends application_version=0. Omitting the NGD records, substituting 97563, or labeling the final record S2/Mc64 produces a different and invalid version set.

8.3 Configuration and proof

C -> S  Auth/1   ResumeRequest
S -> C  Auth/18  Configuration
S -> C  Auth/2   ProofRequest [two modules]
C -> S  Auth/2   ProofResponse [one session-proof output]
S -> C  Auth/1   ResumeResponse [phase-two server proof]

The Resume ProofRequest contains two 40-byte module IDs (eight-byte usage prefix plus a 32-byte module identity):

  1. Thumbprint module. The server supplies a 4096-bit RSA PKCS#1 v1.5 SHA-512 signature. Hash the 16-byte connected peer address followed by the ASCII domain Thumbprint.IPv6. IPv4 peers use IPv4-mapped IPv6 form. Verify with exponent 65537 and the public modulus embedded in SC2. This is a one-way server-authentication check and contributes no ModuleOutput element.
  2. Session-proof module. Server data is 00 || server_nonce[16]. Treat the 64-byte GameUtilities value as seed B, generate client_nonce[16], derive the per-challenge key C below, and return 01 || client_nonce || HMAC-SHA256(C, 00 || client_nonce || server_nonce). The successful ResumeResponse returns 02 || HMAC-SHA256(C, 01 || server_nonce || client_nonce), which must be verified.

For GameUtilities seed B, client nonce Nc, and server nonce Ns, the Resume ratchet and proofs are:

C = HMAC-SHA256(B, 0x00 || Nc || Ns)
 || HMAC-SHA256(B, 0x01 || Ns || Nc)

client_proof    = HMAC-SHA256(C, 0x00 || Nc || Ns)
server_proof    = HMAC-SHA256(C, 0x01 || Ns || Nc)
transport_secret = C

Resume first ratchets seed B into C; Auth/2 proofs use C, not B directly. The domain-two KDF belongs to the alternate full-logon handshake and is not part of Resume.

An optional plaintext Conn/11 RegulatorUpdate can appear before Auth/1 ResumeResponse.

8.4 Conn/5 and stream protection

After validating the server proof, the client sends an empty Conn/5 EnableEncryption BSN record in plaintext. Both directions then immediately use ordinary stateful RC4, with no initial keystream discard:

inbound_key  = HMAC-SHA256(transport_secret,
                68e0c72eddd6d2f31e5ab155b18b631e)
outbound_key = HMAC-SHA256(transport_secret,
                dea965ae543a1e939e690caa68de7839)

The two RC4 states are independent and persist across TCP reads, writes, and BSN record boundaries. TCP segmentation is irrelevant. If one receive call contains plaintext ResumeResponse followed by protected bytes, decrypt only the buffered suffix after enabling the inbound state, exactly once.

Once protection is active, the connection enters the service bootstrap covered by the endpoint reference in the next chapter.

Back to contents

9. Native service reference

Native BSN exposes service command endpoints, not BGS protobuf RPC methods. An endpoint is identified by (direction, service FourCC, command). Each entry below separates the stable route from the session-assigned numeric service slot and describes the payload in actual generated order where known.

How to read the payload blocks

The blocks use compact pseudocode created for this reference. It is not Blizzard source, protobuf syntax, or a wire-level DSL.

field Typeone named value of the stated type
[0..50]inclusive element-count or value range
?an optional value controlled by a presence bit
uN / sNunsigned or signed N-bit integer
repeat countdecode the indented structure exactly count times
alignToByteadvance the shared cursor to the next byte
reserved bits[N]consume N bits with no assigned field meaning
choice { … }decode only the arm selected by its discriminator

A range states what values are allowed; it does not by itself define the count encoding. Fields are in actual wire order only when an entry says generated order. Logical order follows metadata member order. Leading m_ prefixes are omitted for readability.

The entries follow the Resume and post-login path. “Logical structure” means metadata member order; “generated order” means the serializer's actual bit order, including any reserved runs inserted for an obfuscated type. Entries with an incomplete structure state the missing portion directly.

9.1 Auth — authentication

These plaintext endpoints bind the Sunken connection to the account and session authorized by Front. The cryptographic sequence is described in Native Resume authentication.

Auth/1 request Auth/18 configuration Auth/2 request Auth/2 response Auth/1 response

Auth/1 Authentication::ResumeRequest

Direction
client → server
Phase
plaintext, first record
Structure
logical order

Starts native authentication with account identity and the version set for the SC2 game account selected on Front.

RequestCommon {
    program    FourCC
    platform   FourCC
    locale     FourCC
    versions   Version[0..63] {
        programId  FourCC
        component  FourCC
        version    u32
    }
}
account            bytes[3..320]
gameAccountRegion  u8
gameAccountName    bytes[1..32]

The Base97563 macOS version records and compatibility number are listed in section 8. Account fields are private session material.

Auth/18 Authentication::Configuration

Direction
server → client
Phase
plaintext
Structure
logical order

Supplies a small authentication configuration record before proof.

useS3Depot  bool

Auth/2 Authentication::ProofRequest

Direction
server → client
Phase
plaintext
Structure
logical order

Requests execution of up to four authentication modules. The array count is explicit: the payload begins with a three-bit count, and the decoder then consumes exactly that many ModuleInput values. Resume encodes count 2 for the thumbprint and session-proof modules.

requestCount  u3  valid values 0..4; 5..7 are invalid
repeat requestCount:
    alignToByte
    id             blob[40]  fixed size; no length prefix
    dataByteCount  u10 0..1023
    alignToByte
    data           bytes[dataByteCount]

The 40-byte module identifier selects the authentication-module implementation that must interpret data. It is not a request token or an identifier for the Auth/2 route. The 2 in Auth/2 is the separate six-bit command ID in the BSN routing header.

id[0..7]    usage             61 75 74 68 00 00 00 00  ASCII "auth" + four NUL bytes
id[8..39]   module identity   opaque 32-byte value

Thumbprint module identity
d7 e6 62 40 80 c1 ab a6 6d ee 63 a6 f3 92 8d 8a
54 69 25 7f 58 20 b5 72 1f b8 c3 2b 6b 5b ef 5d

Session-proof module identity
89 50 05 34 0a 63 0a 64 65 a6 5f ec 96 32 3c 31
0b ca 8a 9f 66 ec ee b1 88 7a 9d 6c 0e 67 61 2e

Resume supplies these two modules in the order shown. The count cannot be inferred from a containing record length, because native BSN has no general record-length field.

Auth/2 Authentication::ProofResponse

Direction
client → server
Phase
plaintext
Structure
logical order

Returns outputs requested by the authentication modules. This is not a one-element-for-every-input array: the thumbprint module is verified locally and emits no output. The Resume response therefore contains one output, belonging to the session-proof module.

responseCount  u3  valid values 0..4; Resume uses 1
repeat responseCount:
    dataByteCount  u10 0..1023
    alignToByte
    data           bytes[dataByteCount]

The session-proof output is 01 || client_nonce[16] || proof[32], for a byte count of 49. No empty thumbprint placeholder is encoded.

Auth/1 Authentication::ResumeResponse

Direction
server → client
Phase
plaintext
Structure
logical order

Completes Resume. A successful response carries the phase-two server proof; a failure carries an update, error/wait pair, or version-check disconnect.

result  choice {
    success {
        finalRequestCount  u3 0..4
        finalRequest       ModuleInput[finalRequestCount]
        pingTimeout     Time::Delta
        regulatorRules  optional RegulatorRules
    }
    failure {
        strings  optional Cache::Handle[40]
        result   choice { update | failure { error, wait } | versionCheckDisconnect }
    }
}

9.2 Conn — connection control

Connection endpoints report failures and bootstrap state, activate transport protection, and carry routed application frames.

Conn/1Conn/3 Conn/5Conn/10 Conn/11Conn/13 Conn/14

Conn/1 Connection::Boom

Direction
server → client
Phase
failure path
Structure
logical order

Terminates the native session with a numeric protocol error.

error  u16 Error::Code

Conn/3 Connection::ServerVersion

Direction
server → client
Phase
protected bootstrap
Structure
32-bit shape

The 32-bit payload has the embedded ServerVersion shape. The command-to-handler name remains provisional, but the payload boundary is unambiguous.

version  u32

Conn/5 Connection::EnableEncryption

Direction
client → server
Phase
last plaintext record
Structure
empty payload

Commits the connection to independent inbound and outbound RC4 streams. Protection begins immediately after this empty record.

EnableEncryption { }  zero payload bits

Conn/10 Connection::Ping

Direction
client → server
Phase
protected keepalive
Structure
generated order

The client sends this record roughly once per minute. Its optional signed value is the current Unix epoch timestamp in microseconds. Omitting the ping eventually makes the server close an otherwise healthy chat session.

timeData  optional s64  Unix epoch microseconds

Conn/11 Connection::RegulatorUpdate

Direction
server → client
Phase
plaintext or protected
Structure
logical order

Updates the connection rate regulator. It may appear immediately before ResumeResponse.

info  choice {
    none
    leakyBucket {
        threshold  u32
        rate       u32
    }
}

Conn/13 Connection::MessageFrame

Direction
bidirectional
Phase
protected
Structure
generated order

Carries a generic routed application envelope. A route header inside the frame can name another service by stable FourCC and command, independently of the outer runtime service slot.

payload    blob[0..14336]
frameType  u8 enum CS_ROUTED, SS_ROUTED, SS_BROADCAST, SS_ERROR, SC_ERROR, SC_ROUTED, SC_BROADCAST
headers    Header[0..32]

Header = choice {
    content | route | target | correlation | client | service
    error | replicate | timestamp | stream | traceRoute
}

Reflection lists frame type and headers before the payload. Using that order corrupts the following record.

Retail also emits two independent maintenance requests to the TrnC route once per minute: command 3 carries four zero bytes and command 2 carries the stable 11-byte payload 030080057e4002020a0301. Both are CS_ROUTED frames with route, correlation, content, and stream headers. Their correlation headers set reply = false, so these are periodic client requests, not replies to a server challenge. A chat-only client must emit them in addition to Conn/10 Ping to match retail idle-session behavior.

Conn/14 Connection::GameSiteInfo

Direction
server → client
Phase
first protected bootstrap
Structure
generated order

Announces the client's public IPv4 endpoint as seen by the service, plus the available SC2 game sites.

externalIp4Addr  IP4::AddressPort { address, port }
siteData            SiteDataForClient[0..64] {
    name         bytes[0..32]
    addressPort  optional IP4::AddressPort
}

9.3 Toon — identity and bootstrap

Toon endpoints provide the account's playable identities and global SC2 bootstrap configuration.

Toon/0 ToonListToon/5 ToonSelectToon/6 ToonSelectedToon/10 WelcomeToon/14 InitialNotifiesComplete

Toon/0 Toon::ToonList

Direction
server → client
Phase
protected bootstrap
Structure
generated order

Lists up to fifty toon display records owned by the authenticated account.

toonDisplayCount  u6  valid values 0..50
repeat toonDisplayCount:
    Display {
        nameByteCountMinus2  u7
        alignToByte
        name        UTF-8 bytes[nameByteCountMinus2 + 2]
                    2..100 bytes; 2..25 characters
        lastOnline  s32
        reserved    bits[3]
        flags       u32
        profile     Profile::RecordAddress
        realm       u32
    }

Toon/5 Toon::ToonSelect

Direction
client → server
Phase
protected bootstrap
Structure
generated order

Selects one display returned by Toon/0 before channel discovery and join. A successful selection is followed by Toon/6.

nameByteCountMinus2  u7
alignToByte
toonName             UTF-8 bytes 2..100 bytes; 2..25 characters
generatedCheck       u10 rolling check seeded with 2
realm                u32

Reflection lists name then realm, but omits the generated rolling check between them.

Toon/6 Toon::ToonSelected

Direction
server → client
Phase
protected bootstrap
Structure
generated order

Confirms the active SC2 identity and returns its stable handle and profile address.

recordAddress  { label u32, id u64 }
toonHandle     { program FourCC, region u8, realm u32, id u64 }
realm          u32
lastLogon      s32
nameByteCountMinus2  u7
alignToByte
toonName       UTF-8 bytes

Toon/10 Toon::Welcome

Direction
server → client
Phase
protected bootstrap
Structure
generated order

Supplies global client configuration. This is a heavily obfuscated schema: generated code reorders reflected members and consumes reserved runs.

depotRegion                    FourCC
achievementHandles              AchievementHandle[0..15]
isPlayingFromIGR                 bool
defaultPortrait                  u32
reserved                         bits[31]
maxGameServerConnectTimeoutMS    u32
programName                     bytes[0..32]
programFlags                    bits[128]
realmMapList                    RealmMap[0..4]
unlockablesFiles                UnlockableDefinition[0..128]
reserved                         bits[3]
maxMapFavorites                 u16
intermediateNameRestriction     UTF-8[0..1024]
finalNameRestriction            UTF-8[0..1024]
currentTime                     s32

Toon/14 Toon::InitialNotifiesComplete

Direction
server → client
Phase
protected bootstrap
Structure
empty payload

Marks completion of the initial Toon notification set.

InitialNotifiesComplete { }  zero payload bits

9.4 Pres — presence

Presence begins by defining a dynamic field table. Later updates carry field handles plus a length-framed data blob whose individual values depend on that table.

Pres/1 FieldSpecAnnouncePres/0 UpdateNotify

Pres/1 Presence::FieldSpecAnnounce

Direction
server → client
Phase
protected bootstrap
Structure
generated order

Defines the numeric handles and storage rules used by subsequent presence updates.

definitionCount  u7 0..100 accepted by the current client
repeat definitionCount:
    clientOnly   bool
    writable     bool
    ephemeral    bool
    sizeKind     u1 0 = fixed, 1 = variable
    fixedSize?   u16
    serverOnly   bool
    identifier   u8
    handle       u32

Pres/0 Presence::UpdateNotify

Direction
server → client
Phase
protected
Structure
generated order

Updates online state and one or more dynamically announced fields. The field data is sliced in handle order using each Pres/1 fixed size or the next variable size. Cleared handles remove retained values. Local and master presence IDs are aliases for the same retained record.

reserved           bits[19]
online             bool
localPresenceId    u32
masterPresenceId   u32
fieldDataByteCount u11 0..1024
alignToByte
fieldData          bytes[fieldDataByteCount]
reserved           bits[11]
clearedHandles     u32[count:u4]
handles            u32[count:u4]
variableSizes      u16[count:u4]
levelZero?         { isLastPacket bool, target u32 }
serverOnly         u8

FIELD_AVATAR (65555) is a four-byte ImageTableEntry. Public channel membership usually supplies FIELD_TOON_PROFILE (65556) instead; its 12-byte profile address is followed through Prfl/0 path 04 to obtain the selected avatar.

9.5 Frnd — friends and blocks

These paged notifications carry the initial friends and block lists and can later carry incremental changes.

Frnd/30 FriendsListNotify5Frnd/31 AccountBlockAddedNotifyFrnd/33 ToonBlockNotify

Frnd/30 Friends::FriendsListNotify5

Direction
server → client
Phase
protected bootstrap and updates
Structure
generated order

Pages additions, removals, and modifications for account, character, and presence-only friend containers.

endOfInitial?  bool
updateCount    u7 0..64
repeat updateCount:
    operation  choice { add | remove | modify }
    subject    choice { character | account | presence }

Nested account and character records contain private names, notes, profile addresses, and presence values. Those private leaf values are omitted here; the enclosing wire structure is unchanged.

Frnd/31 Friends::AccountBlockAddedNotify

Direction
server → client
Phase
protected bootstrap and updates
Structure
generated order
endOfInitial?  bool
entryCount      u7 0..64
repeat entryCount:
    accountId  u32
    fullName?  optional value
    nickname?  UTF-8
    role       u32

Frnd/33 Friends::ToonBlockNotify

Direction
server → client
Phase
protected bootstrap
Structure
generated order
entryCount      u7
endOfInitial?   bool

Only the empty-page form is currently defined. The generated order of a non-empty toon-block entry remains unresolved.

9.6 Cach — cache streams

Cach/9 requestCach/9 response

Cach/9 Cache::GetStreamItemsRequest

Direction
client → server
Phase
protected bootstrap
Structure
generated order

Requests items from a named cache stream. The chat bootstrap uses channel BNET and item name CONF.

token          u32
generatedCheck u23 rolling check seeded with 7
maxItemsMinus1 u6 request range 1..50
streamKind     u1 1 = description
channel        FourCC
itemName       FourCC
locale         FourCC
referenceTime  s32
direction      u1 0 = before, 1 = after

Cach/9 Cache::GetStreamItemsResponse

Direction
server → client
Phase
protected bootstrap
Structure
generated order
itemCount  u6 0..49
repeat itemCount:
    reserved         bits[23]
    alignToByte
    contentHandle  blob[40]
    publicationTime s32
token       u32
totalItems  u16
offset      u16

9.7 S2Ms — SC2 master data

S2Ms/27 CurrentSeasonResponse

S2Ms/27 S2Master::CurrentSeasonResponse

Direction
server → client
Phase
protected bootstrap
Structure
generated order

Returns either a 16-bit error or the current authority, matchmaker, league, season, and league-configuration data.

result  choice {
    success {
        authorityState       bool
        rankedMatchmakers     RankedMatchmakerConfig[count:u7]
        leagues               League[count:u9]
        seasonInfo           SeasonInfo
        leagueConfigurations LeagueConfig[count:u9]
    }
    failure  u16
}

The generated order includes reserved runs and reordered nested members that are absent from logical metadata.

9.8 S2Mp — SC2 multiplayer configuration

S2Mp/57 ClubSettings

S2Mp/57 Club::ClubSettings

Direction
server → client
Phase
protected bootstrap
Structure
generated order

Supplies club-name and tag validation expressions plus cache size and expiry policy.

namePattern          UTF-8 u13 byte count; up to 4096 bytes
tagPattern           UTF-8 u13 byte count; up to 4096 bytes
informationCacheSize u32
memberCacheSize      u32
informationExpiry    s32
onlineStatusExpiry   s32
eventExpiry          s32

9.9 Prfl — profile data

The FourCC is Prfl; embedded type names use the full Profile namespace.

Prfl/0 ReadPrfl/4 SettingsAvailable

Prfl/0 Profile::Read

Direction
bidirectional
Phase
protected
Structure
generated order

Reads a field path from a profile record. Roster avatar resolution uses the profile address advertised by presence and path 04, the zero-based position of ToonProfile.m_avatar.

client → server
clientHash     u32
requestId      u32
recordAddress  Profile::RecordAddress
readFlags      bits[5]
pathLength     u8
path           bytes[pathLength]

server → client
result         choice { Start, Block, Failure, Cache }
requestId      u32

Both directions differ from reflection member order. A returned avatar is an ImageTableEntry containing the retail ICON atlas ID and row-major cell offset.

Prfl/4 Profile::SettingsAvailable

Direction
server → client
Phase
protected bootstrap
Structure
generated order

Announces a profile settings record that can be addressed by type, field path, and record address.

type     enum { 1=SETTING_ACCOUNT, 2=SETTING_GAME, 3=SETTING_TOON }
path     blob[0..32]
address  Profile::RecordAddress { label, id }

Reflection lists address before path. The generated client reads type, path, then address.

9.10 Chat — channels, roster, and messages

The four-bit service slot in the outer route selects the Chat service. The separate three-bit channelIndex inside Chat payloads selects one of the rooms already joined by this client; it is returned by a successful join and must be preserved for later message, roster, and leave records.

bootstrap order Chat/21Chat/22 Chat/25Chat/26 Chat/0Chat/1 Chat/2Chat/11 send Chat/11 receiveChat/27Chat/32 Chat/33

Becoming ready to join chat

Entering the protected BSN stream does not immediately make the session chat-ready. Base97563 establishes the playable identity and loads the regional channel directory before it attempts a join:

  1. Request Cach/9 stream item BNET/CONF/enUS.
  2. When Toon/0 supplies the account's playable identities, choose one with Toon/5. Wait for both the cache response and Toon/6.
  3. Send Chat/25 and Chat/21. Collect Chat/26 pages until isLast is true, and wait for Chat/22.
  4. Send Chat/0 for the desired public or private channel. A successful Chat/27 assigns the channelIndex and local member handle.
  5. Apply Chat/1 membership batches until endOfInitial is true. The roster is then complete and the assigned channel index can be used by Chat/11 and Chat/2.

These are state dependencies, not TCP adjacency rules. Other protected records may appear between them, so a client must continue dispatching every complete record while it waits for each milestone.

Chat/21 Chat::ChannelListRequest

Direction
client → server
Phase
protected discovery
Structure
empty payload

Requests the account's current channel-list descriptors.

ChannelListRequest { }  zero payload bits

Chat/22 Chat::ChannelListResponse

Direction
server → client
Phase
protected discovery
Structure
generated order

Returns auto-join and recently joined channel descriptors.

reserved    bits[37] 27 + 1 + 9 generated bits
entryCount  u6
repeat entryCount:
    kind        u8
    index       u16
    reserved    bits[24]
identifier  u16

The descriptor identifier is not a public ChannelNameStringId and cannot be copied into a public join.

Chat/25 Chat::EnumConferenceDescriptions

Direction
client → server
Phase
protected discovery
Structure
empty payload

Requests the regional public-conference catalog.

EnumConferenceDescriptions { }  zero payload bits

Chat/26 Chat::ConferenceDescriptions

Direction
server → client
Phase
protected discovery
Structure
generated order

Returns one page of public numeric conference descriptions.

isLast       bool
reserved     bits[27]
decoy?        s32
entryCount   u6
repeat entryCount:
    reserved   bits[23]
    identifier u32
    sortOrder  u16
    marker     bool

Chat/0 Chat::JoinRequest2

Direction
client → server
Phase
protected
Structure
logical order

Requests membership in a private, public, or club conference.

token  u32
key    Conference::LocatorKey choice {
    0 private  UTF-8[0..31 chars, 0..124 bytes]
    2 public   { locale FourCC, name u16 }
    3 club     { club u32 }
}

Choice value 1 has no defined arm. Generated code writes the locator before the request token. The private arm uses a seven-bit UTF-8 byte count, byte alignment, and then the name bytes. Both public ID 1033 and a named private room have been acknowledged live.

Chat/27 Chat::JoinNotify2

Direction
server → client
Phase
protected
Structure
generated order

Acknowledges or rejects a join and assigns the local channel index used by membership, message, and leave records.

result  choice {
    0 success { memberHandle u32, channelIndex u3,
                voiceSessionId, channelType u4,
                name?, config?, inviter? }
    1 failure { reason u16, channelType? u4 }
}
token?  u32

The generated decoder is result-first/token-last and includes reserved runs absent from reflection metadata.

Chat/1 Chat notify family

Direction
server → client
Phase
protected
Structure
generated order

Command 1 carries MembershipChangeNotify, which creates the initial roster and then applies incremental membership changes.

endOfInitial  bool
channelIndex  u3 0..6
changes       MembershipChange[1..64]

MembershipChange = choice {
    leaving
    joining       member handle, presence ID, status values
    updateStatus  member handle, one status value
}

endOfInitial marks completion of the initial roster snapshot. Generated ToonName status values provide display names directly. After the initial snapshot, the same structure carries joins, leaves, and status changes.

Chat/2 Chat::LeaveRequest

Direction
client → server
Phase
protected
Structure
logical order

Leaves one locally tracked chat room.

channelIndex  u3 0..6

Chat/11 Chat::MessageSend

Direction
client → server
Phase
protected
Structure
generated order

Sends a UTF-8 message to one joined room.

bodyByteCount  u10 0..1020
alignToByte      zero bits
body             UTF-8 bytes
channelIndex     u3 0..6

Generated validation separately limits the body to 255 Unicode characters. Reflection lists channel index before body.

Chat/11 Chat::MessageRecv

Direction
server → client
Phase
protected
Structure
generated order

Delivers a message with the sender's channel-local member handle.

memberHandle   u32
bodyByteCount  u10 0..1020
alignToByte      zero bits
body             UTF-8 bytes
channelIndex     u3 0..6

The 32-bit handle starts at the payload's current bit position and is not necessarily byte-aligned in the complete record.

Chat/32 Chat::ModifyChannelListRequest2

Direction
client → server
Phase
protected
Structure
logical order

Adds or updates an auto-join or recently-joined channel-list entry.

token  u32
index  u8
key    Conference::LocatorKey
type   u1 enum { 0=AUTO_JOIN, 1=RECENTLY_JOINED }

Chat/33 Chat::ModifyChannelListResponse2

Direction
server → client
Phase
protected
Structure
logical order

Correlates to Chat/32 by token and reports success or failure.

token   u32
result  choice {
    0 success  s32 time value
    1 failure  u16 error code
}

Back to contents

10. Unresolved portions

  1. Frnd/33 is defined for an empty page; the generated order of a non-empty toon-block entry remains unknown.
  2. Server echo of an outbound Chat/11 message still needs explicit verification. Automated validation remains passive and never sends chat.
  3. Numeric public-channel identifiers still need a reliable source of localized display names.
  4. Additional registry services and commands remain metadata-only until their command mappings and generated wire orders are established.

Back to contents

11. Glossary

Battle.net platform
The complete modern account and game-service system. It includes BGS, web authentication, GameUtilities, and game-native services.
BGS (Battle.net Game Services)
The protobuf RPC layer carried here as one RPC per WebSocket binary message inside TLS. BGS handles generic connection, authentication, challenge, account, and GameUtilities calls.
BGS WebSocket
The RFC 6455 transport selected with subprotocol v1.rpc.battle.net. Its binary-message boundary delimits the complete BGS RPC body when the protobuf header omits size.
Cached web credential
An opaque value returned by AuthenticationServer method 8 after successful authentication and offered in a later LogonRequest. It is distinct from the short-lived credential returned by the interactive web challenge.
BSN
This document's short name for SC2's native, bit-packed service protocol. It is schema-delimited and routed by service slot and command.
Front
The regional SC2 BGS connection used before the native handoff.
Sunken
The SC2-native endpoint that accepts Resume authentication and then carries protected BSN service traffic.
GameUtilities
A generic BGS service. Its ProcessClientRequest method performs the SC2-specific Front-to-Sunken handoff on this path.
Protobuf descriptor
Schema metadata for a BGS message or service. BGS service names and methods are recoverable from standard protobuf descriptors embedded in the client.
BSN metadata
SC2's separate version-7 native type library, embedded in the executable rather than sent in BSN records. A numeric type ID selects a structural record and an optional naming record; recursively resolving child IDs produces the logical payload schema. It is not a protobuf descriptor set.
Frame
A BGS header/body unit, or the explicitly named native Connection/13 MessageFrame. The term is not used as a synonym for every native BSN record.
Packet
A convenient but ambiguous informal term. This document prefers BGS frame, BSN record, and TCP segment because each has a different boundary.
Record
One native BSN route header plus its schema-delimited payload and final byte-boundary padding.
Schema-delimited
A record boundary determined by executing the route-selected payload schema, rather than by reading an outer record-length field. Local counts, selectors, and presence bits determine nested extents; completion of the top-level value determines the logical record end.
Route
The native tuple (direction, service FourCC, command). Direction matters because the same command number may name different request and notify types.
Service hash
A 32-bit FNV-1a hash of a full protobuf service name, used for BGS dispatch after the initial Connect.
BGS token
A protobuf-header correlation value joining an RPC response or callback acknowledgement to the corresponding call. It is unrelated to a Chat request's application-level m_token.
Authentication module ID
The 40-byte identifier in an Auth/2 ModuleInput: an eight-byte usage prefix followed by a 32-byte opaque module identity. It selects how that module's data is processed. A module may produce no response element: in Resume, the locally checked thumbprint produces none and the session-proof module produces the sole output. See the exact layout and known IDs.
Service slot
A session-local four-bit number selecting a native BSN service. It is not a chat channel.
Client channel index
A three-bit Chat payload field selecting one of up to seven locally tracked chat channels. It is independent of the native service slot.
LocatorKey
A native Chat choice identifying a private, public, or club conference. Public channels use a locale FourCC and a channel-name string ID.
Generated order
The actual field order emitted by SC2's generated native serializer. For an obfuscated type it may differ from reflection-member order and may include otherwise unnamed reserved bits.
Resume
Blizzard’s name for the native Auth exchange that continues Front-authorized account, game-account, and key context on a new Sunken connection. The exact names Authentication::ResumeRequest and Authentication::ResumeResponse occur in SC2’s embedded BSN metadata. It does not mean resuming the previous TCP socket or restoring an earlier chat or game session. See the nomenclature explanation.
NO_RESPONSE
A protobuf RPC declaration stating that a BGS callback has no reply frame. It is semantically different from a response whose protobuf body is empty.
FourCC
A four-byte symbolic identifier such as Chat, Auth, Mc64, or enUS.

Back to contents

12. Prior art and source material

The 6+1+4 bit header and unusual bit order were publicly described during the original Battle.net 2 era. The sources below also provide protobuf, replay-format, and GameUtilities context useful when interpreting the live SC2 protocols.

Back to top