CoreProtocol - The inner workings

Smartglass protocol core

NOTE: Should not be used directly, use Console !

exception xbox.sg.protocol.ProtocolError

Bases: Exception

Exception thrown by CoreProtocol

class xbox.sg.protocol.SmartglassProtocol(address: Optional[str] = None, crypto_instance: Optional[xbox.sg.crypto.Crypto] = None)

Bases: asyncio.protocols.DatagramProtocol

HEARTBEAT_INTERVAL = 3.0
__init__(address: Optional[str] = None, crypto_instance: Optional[xbox.sg.crypto.Crypto] = None)

Instantiate Smartglass Protocol handler.

Parameters
  • address – Address

  • crypto_instance – Crypto instance

async stop()None

Dummy

connection_made(transport: asyncio.transports.DatagramTransport)None

Called when a connection is made.

The argument is the transport representing the pipe connection. To receive data, wait for data_received() calls. When the connection is closed, connection_lost() is called.

error_received(exc: OSError)

Called when a send or receive operation raises an OSError.

(Other than BlockingIOError or InterruptedError.)

connection_lost(exc: Optional[Exception])

Called when the connection is lost or closed.

The argument is an exception object or None (the latter meaning a regular EOF is received or the connection was aborted or closed).

async send_message(msg, channel=<ServiceChannel.Core: 0>, addr: Optional[str] = None, blocking: bool = True, timeout: int = 5, retries: int = 3) → Optional[xbox.sg.utils.struct.XStruct]

Send message to console.

Packing and encryption happens here.

Parameters
  • msg – Unassembled message to send

  • channel – Channel to send the message on, Enum member of ServiceChannel

  • addr – IP address of target console

  • blocking – If set and msg is Message-packet, wait for ack

  • timeout – Seconds to wait for ack, only useful if blocking is True

  • retries – Max retry count.

Returns: None

Raises

ProtocolError – On failure

async _send(data: bytes, target: Tuple[str, int])

Send data on the connected transport.

If addr is not provided, the target address that was used at the time of instantiating the protocol is used. (e.g. asyncio.create_datagram_endpoint in Console-class).

Parameters
  • data – Data to send

  • target – Tuple of (ip_address, port)

datagram_received(data: bytes, addr: str)None

Handle incoming smartglass packets

Parameters
  • data – Raw packet

  • addr – IP address of sender

Returns: None

async _await_ack(identifier: str, timeout: int = 5) → Optional[xbox.sg.utils.struct.XStruct]

Wait for acknowledgement of message

Parameters
  • identifier – Identifier of ack

  • timeout – Timeout in seconds

Returns

Event

Return type

Event

_set_result(identifier: str, result: Union[xbox.sg.enum.AckStatus, xbox.sg.utils.struct.XStruct])None

Called when an acknowledgement comes in, unblocks _await_ack

Parameters
  • identifier – Identifier of ack

  • result – Ack status

Returns: None

async _heartbeat_task()None

Task checking for console activity, firing on_timeout-event on timeout.

Heartbeats are empty “ack” messages that are to be ack’d by the console

Returns

None

_on_message(msg: xbox.sg.utils.struct.XStruct, channel: xbox.sg.enum.ServiceChannel)None

Handle msg of type Message.

Parameters
  • msg – Message

  • channel – Channel the message was received on

Returns: None

_on_ack(msg: xbox.sg.utils.struct.XStruct)None

Process acknowledgement message.

Parameters

msg – Message

Returns: None

_on_json(msg: xbox.sg.utils.struct.XStruct, channel: xbox.sg.enum.ServiceChannel)None

Process json message.

Parameters
  • msg – Message

  • channel – Channel the message was received on

Returns: None

async discover(addr: str = None, tries: int = 5, blocking: bool = True, timeout: int = 5) → Dict[str, xbox.sg.utils.struct.XStruct]

Discover consoles on the network

Parameters
  • addr (str) – IP address

  • tries (int) – Discover attempts

  • blocking (bool) – Wait a given time for responses, otherwise return immediately

  • timeout (int) – Timeout in seconds (only if blocking is True)

Returns

List of discovered consoles

Return type

list

property discovered

Return discovered consoles

Returns

Discovered consoles

async connect(userhash: str, xsts_token: str, client_uuid: uuid.UUID = UUID('cf21c4a1-99cd-47c9-9fd4-c38626d33ca4'), request_num: int = 0, retries: int = 3)xbox.sg.enum.PairedIdentityState

Connect to console

Parameters
  • userhash – Userhash from Xbox Live Authentication

  • xsts_token – XSTS Token from Xbox Live Authentication

  • client_uuid – Client UUID (default: Generate random uuid)

  • request_num – Request number

  • retries – Max. connect attempts

Returns: Pairing State

Raises

ProtocolError – If connection fails

async local_join(client_info: Union[xbox.sg.constants.WindowsClientInfo, xbox.sg.constants.AndroidClientInfo] = <class 'xbox.sg.constants.WindowsClientInfo'>, **kwargs)None

Pair client with console.

Parameters
  • client_info – Either WindowsClientInfo or AndroidClientInfo

  • **kwargs

Returns: None

async start_channel(channel: xbox.sg.enum.ServiceChannel, messagetarget_uuid: uuid.UUID, title_id: int = 0, activity_id: int = 0, **kwargs)None

Request opening of specific ServiceChannel

Parameters
  • channel – Channel to start

  • messagetarget_uuid – Message Target UUID

  • title_id – Title ID, Only used for ServiceChannel.Title

  • activity_id – Activity ID, unknown use-case

  • **kwargs – KwArgs

Returns: None

async ack(processed: List[int], rejected: List[int], channel: xbox.sg.enum.ServiceChannel, need_ack: bool = False)None

Acknowledge received messages that have need_ack flag set.

Parameters
  • processed – Processed sequence numbers

  • rejected – Rejected sequence numbers

  • channel – Channel to send the ack on

  • need_ack – Whether we want this ack to be acknowledged by the target participant. Will be blocking if set. Required for heartbeat messages.

Returns: None

async json(data: str, channel: xbox.sg.enum.ServiceChannel)None

Send json message

Parameters
  • data – JSON dict

  • channel – Channel to send the message to

Returns: None

async power_on(liveid: str, addr: Optional[str] = None, tries: int = 2)None

Power on console.

Parameters
  • liveid – Live ID of console

  • addr – IP address of console

  • tries – PowerOn attempts

Returns: None

async power_off(liveid: str)None

Power off console

Parameters

liveid – Live ID of console

Returns: None

async disconnect(reason: xbox.sg.enum.DisconnectReason = <DisconnectReason.Unspecified: 0>, error: int = 0)None

Disconnect console session

Parameters
  • reason – Disconnect reason

  • error – Error Code

Returns: None

async game_dvr_record(start_delta: int, end_delta: int)xbox.sg.enum.AckStatus

Start Game DVR recording

Parameters
  • start_delta – Start time

  • end_delta – End time

Returns: Acknowledgement status

async launch_title(uri: str, location: xbox.sg.enum.ActiveTitleLocation = <ActiveTitleLocation.Full: 0>)xbox.sg.enum.AckStatus

Launch title via URI

Parameters
  • uri – Uri string

  • location – Location

Returns: Ack status

class xbox.sg.protocol.SequenceManager

Bases: object

__init__()

Process received messages by sequence numbers. Also add processed / rejected messages to a list. Tracks the Low Watermark that’s sent with Acknowledgement-Messages too.

add_received(sequence_num: int)None

Add received sequence number

Parameters

sequence_num – Sequence number

Returns: None

add_processed(sequence_num: int)None

Add sequence number of message that was sent to console and succeeded in processing.

Parameters

sequence_num – Sequence number

Returns: None

add_rejected(sequence_num: int)None

Add sequence number of message that was sent to console and was rejected by it.

Parameters

sequence_num – Sequence number

Returns: None

next_sequence_num()int

Get next sequence number to use for outbound Message.

Returns: None

property low_watermark

Get current Low Watermark

Returns: Low Watermark

exception xbox.sg.protocol.ChannelError

Bases: Exception

Exception thrown by ChannelManager.

class xbox.sg.protocol.ChannelManager

Bases: object

CHANNEL_CORE = 0
CHANNEL_ACK = 1152921504606846976
__init__()

Keep track of established ServiceChannels

handle_channel_start_response(msg: xbox.sg.utils.struct.XStruct)xbox.sg.enum.ServiceChannel

Handle message of type StartChannelResponse

Parameters

msg – Start Channel Response message

Raises

ChannelError – If channel acquire failed

Returns: Acquired ServiceChannel

get_next_request_id(channel: xbox.sg.enum.ServiceChannel)int

Get next Channel request id for ServiceChannel

Incremented on each call.

Parameters

channel – Service channel

Returns: Channel request id

get_channel(channel_id: int)xbox.sg.enum.ServiceChannel

Get matching ServiceChannel enum for provided Channel ID of Message

Parameters

channel_id – Channel of Message

Returns: Service channel

get_channel_id(channel: xbox.sg.enum.ServiceChannel)int

Get Channel ID for use in Message for provided ServiceChannel

Parameters

channel – Service channel

Returns: Channel ID for use in Message

reset()None

Erase the channels table

Returns

None

exception xbox.sg.protocol.FragmentError

Bases: Exception

Exception thrown by FragmentManager.

class xbox.sg.protocol.FragmentManager

Bases: object

Assembles fragmented messages

reassemble_message(msg: xbox.sg.utils.struct.XStruct) → Optional[xbox.sg.utils.struct.XStruct]

Reassemble message fragment

Parameters

msg – Message fragment

Returns: Reassembled / decoded payload on success,

None if payload is not ready or assembly failed.

reassemble_json(json_msg: dict) → Optional[dict]

Reassemble fragmented json message

Parameters

json_msg – Fragmented json message

Returns: Reassembled / Decoded json object on success,

None if datagram is not ready or assembly failed

static _encode(obj: dict)str

Dump a dict as json string, then encode with base64

Parameters

obj – Dict to encode

Returns: base64 encoded string

static _decode(data: str)dict

Decode a base64 encoded json object

Parameters

data – Base64 string

Returns: Decoded json object

xbox.sg.protocol._fragment_connect_request(crypto_instance: xbox.sg.crypto.Crypto, client_uuid: uuid.UUID, pubkey_type: xbox.sg.enum.PublicKeyType, pubkey: bytes, userhash: str, auth_token: str, request_num: int = 0) → List

Internal method to fragment ConnectRequest.

Parameters
  • crypto_instance – Instance of Crypto

  • client_uuid – Client UUID

  • Public Key Type (pubkey_type) –

  • pubkey – Public Key

  • userhash – Xbox Live Account userhash

  • auth_token – Xbox Live Account authentication token (XSTS)

  • request_num – Request Number

Returns

List of ConnectRequest fragments

Return type

list