<!-- source: docs/api/2_capi/relay/connect.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/connect -->

# Connect

Start off a connection, based off connection type to brainCloud's Relay Servers. Connect options come in from "ROOM_ASSIGNED" lobby callback

## Method Parameters

| Parameter      | Description                                            |
| -------------- | ------------------------------------------------------ |
| connectionType | The connection type. INVALID, WEBSOCKET, TCP, UDP, MAX |
| options        | Options sent in the connection                         |

## Usage

**C#:**

```csharp
RelayConnectionType connectionType = RelayConnectionType.WEBSOCKET;
Dictionary<string, object> options = null;

SuccessCallback successCallback = (response, cbObject) =>
{
    Debug.Log(string.Format("Success | {0}", response));
};
FailureCallback failureCallback = (status, code, error, cbObject) =>
{
    Debug.Log(string.Format("Failed | {0}  {1}  {2}", status, code, error));
};

_bc.RelayService.Connect(connectionType, options, successCallback, failureCallback);
```

**C++:**

```cpp
_bc->getRelayService()->connect(eRelayConnectionType.WEBSOCKET, server.host, port, server.passcode, server.lobbyId, this);
```

**Obj-C:**

```cpp
_bc->getRelayService()->connect(eRelayConnectionType.WEBSOCKET, server.host, port, server.passcode, server.lobbyId, this);
```

**Java:**

```cpp
_bc->getRelayService()->connect(eRelayConnectionType.WEBSOCKET, server.host, port, server.passcode, server.lobbyId, this);
```

**JavaScript:**

```javascript
_bc.relay.connect(eRelayConnectionType.WEBSOCKET, server.host, port, server.passcode, server.lobbyId, result =>
{
    var status = result.status;
    console.log(status + " : " + JSON.stringify(result, null, 2));
});
```

**Dart:**

```dart
void successCallback(Map<String, dynamic>?  jsonResponse) {
    // Did connect.
    // Your code
}
void failureCallback(Map<String, dynamic>?  jsonError) {
  dynamic errorMap = (jsonError is String) ? json.decode(jsonError) : jsonError;
  // Your code
}
// data is retrieved from the onLobby event ROOM_ASSIGNED here.
RelayConnectOptions connectOptions = RelayConnectOptions(
                  false,
                  data["connectData"]["address"],
                  data["connectData"]["ports"]["ws"],
                  data["passcode"],
                  data["lobbyId"]);
​
ServerResponse result = await _bc.relayService.connect(eRelayConnectionType:RelayConnectionType.WEBSOCKET, options:connectOptions, onSuccess:successCallback, onFailure:failureCallback);
```

**Roblox:**

```lua
-- options come from the lobby ROOM_ASSIGNED event
local options = {
    host = data.connectData.address,
    port = data.connectData.ports.ws,
    ssl = false,
    passcode = data.passcode,
    lobbyId = data.lobbyId
}
local successCallback = function(response)
    -- connected
end
local failureCallback = function(response)
    -- your code
end

_bc.relay:connect(options, successCallback, failureCallback)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
-- `room` is the data of the lobby ROOM_READY event (see registerRTTLobbyCallback).
local connectionType = _bc.relay.ConnectionType.UDP
local options = {
    host = room.connectData.address,
    port = room.connectData.ports.udp,
    passcode = room.passcode,
    lobbyId = room.lobbyId
}

local onSuccess = function(message)
    print("Connected to relay server")
end
local onFailure = function(message)
    print("Relay connection failed | " .. tostring(message))
end

_bc.relay:connect(connectionType, options, onSuccess, onFailure)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/deregisterrelaycallback.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/deregisterrelaycallback -->

# DeregisterRelayCallback

Deregisters callback for relay messages coming from peers.

## Usage

**C#:**

```csharp
_bc.RelayService.DeregisterRelayCallback();
```

**C++:**

```cpp
_bc->getRelayService()->deregisterRelayCallback();
```

**Obj-C:**

```cpp
_bc->getRelayService()->deregisterRelayCallback();
```

**Java:**

```cpp
_bc->getRelayService()->deregisterRelayCallback();
```

**JavaScript:**

```javascript
_bc.relay.deregisterRelayCallback();
```

**Dart:**

```dart
// Cloud Code only. To view example, switch to the Cloud Code tab
```

**Roblox:**

```lua
_bc.relay:deregisterRelayCallback()
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
_bc.relay:deregisterRelayCallback()
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/deregistersystemcallback.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/deregistersystemcallback -->

# DeregisterSystemCallback

Deregister callback for RelayServer system messages.

## Usage

**C#:**

```csharp
_bc.RelayService.DeregisterSystemCallback();
```

**C++:**

```cpp
_bc->getRelayService()->deregisterSystemCallback();
```

**Obj-C:**

```cpp
_bc->getRelayService()->deregisterSystemCallback();
```

**Java:**

```cpp
_bc->getRelayService()->deregisterSystemCallback();
```

**JavaScript:**

```javascript
_bc.relay.deregisterSystemCallback();
```

**Dart:**

```dart
// Cloud Code only. To view example, switch to the Cloud Code tab
```

**Roblox:**

```lua
_bc.relay:deregisterSystemCallback()
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
_bc.relay:deregisterSystemCallback()
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/disconnect.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/disconnect -->

# Disconnect

Disconnect from the relay server.

## Usage

**C#:**

```csharp
_bc.RelayService.Disconnect();
```

**C++:**

```cpp
_bc->getRelayService()->disconnect();
```

**Obj-C:**

```cpp
_bc->getRelayService()->disconnect();
```

**Java:**

```cpp
_bc->getRelayService()->disconnect();
```

**JavaScript:**

```javascript
_bc.relay.disconnect();
```

**Dart:**

```dart
// Cloud Code only. To view example, switch to the Cloud Code tab
```

**Roblox:**

```lua
_bc.relay:disconnect()
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
_bc.relay:disconnect()
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/endmatch.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/endmatch -->

# EndMatch

Terminate the match instance by the owner.

## Method Parameters

| Parameter   | Description                                                                       |
| ----------- | --------------------------------------------------------------------------------- |
| payloadJson | payload data sent in JSON format. It will be relayed to other connnected players. |

## Usage

**C#:**

```csharp
string payloadJson = "{\"key\":\"value\"}";

SuccessCallback successCallback = (response, cbObject) =>
{
    Debug.Log(string.Format("Success | {0}", response));
};
FailureCallback failureCallback = (status, code, error, cbObject) =>
{
    Debug.Log(string.Format("Failed | {0}  {1}  {2}", status, code, error));
};

_bc.RelayService.EndMatch(payloadJson, successCallback, failureCallback);
```

**C++:**

```cpp
const char* payloadJson = "{\"key\":\"value\"}";
_bc->getRelayService()->endMatch(payloadJson, this);
```

**Obj-C:**

```cpp
const char* payloadJson = "{\"key\":\"value\"}";
_bc->getRelayService()->endMatch(payloadJson, this);
```

**Java:**

```cpp
const char* payloadJson = "{\"key\":\"value\"}";
_bc->getRelayService()->endMatch(payloadJson, this);
```

**JavaScript:**

```javascript
var payloadJson = {"key":"value"};
_bc.relay.endMatch(payloadJson, result =>
{
    var status = result.status;
    console.log(status + " : " + JSON.stringify(result, null, 2));
});
```

**Dart:**

```dart
var  payloadJson = {"key":"value"};

ServerResponse result = await _bc.relayService.endMatch(payload:payloadJson);

if (result.statusCode == 200) {
    print("Success");
} else {
    print("Failed ${result.error['status_message'] ?? result.error}");
}
```

**Roblox:**

```lua
local json = { key = "value" }

_bc.relay:endMatch(json)
```

**GDScript:**

```gdscript
var payload_json = {"key":"value"}

var result = await _bc.relay_service.end_match(payload_json)

if result.status == 200:
	print("Success")
else:
	print("Failed: %s" % result.status_message)
```

**Lua:**

```lua
local json = { key = "value" }

_bc.relay:endMatch(json)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/getcxidfornetid.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/getcxidfornetid -->

# GetCxIdForNetId

Returns the RTT connection Id associated with a netId.

## Usage

**C#:**

```csharp
_bc.RelayService.GetCxIdForNetId();
```

**C++:**

```cpp
_bc->getRelayService()->getCxIdForNetId();
```

**Obj-C:**

```cpp
_bc->getRelayService()->getCxIdForNetId();
```

**Java:**

```cpp
_bc->getRelayService()->getCxIdForNetId();
```

**JavaScript:**

```javascript
_bc.relay.getCxIdForNetId();
```

**Dart:**

```dart
int aNetId = 2;
​
String cxId = _bc.relayService.getCxIdForNetId(aNetId);
```

**Roblox:**

```lua
local aNetId = 2

local cxId = _bc.relay:getCxIdForNetId(aNetId)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local netId = 1

local cxId = _bc.relay:getCxIdForNetId(netId)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/getnetidforcxid.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/getnetidforcxid -->

# GetNetIdForCxId

Returns the netId associated with a connection Id.

## Usage

**C#:**

```csharp
_bc.RelayService.GetNetIdForCxId();
```

**C++:**

```cpp
_bc->getRelayService()->getNetIdForCxId();
```

**Obj-C:**

```cpp
_bc->getRelayService()->getNetIdForCxId();
```

**Java:**

```cpp
_bc->getRelayService()->getNetIdForCxId();
```

**JavaScript:**

```javascript
_bc.relay.getNetIdForCxId();
```

**Dart:**

```dart
String aCxId = "aaaaaaa";
​
int netId = _bc.relayService.getNetIdForCxId(aCxId);
```

**Roblox:**

```lua
local aCxId = "aaaaaaa"

local netId = _bc.relay:getNetIdForCxId(aCxId)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local cxId = "55555:aaa-bbb-ccc-ddd:asdfjkl"

local netId = _bc.relay:getNetIdForCxId(cxId)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/getnetidforprofileid.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/getnetidforprofileid -->

# GetNetIdForProfileId

Returns the netId associated with a profileId.

## Usage

**C#:**

```csharp
_bc.RelayService.GetNetIdForProfileId();
```

**C++:**

```cpp
_bc->getRelayService()->getNetIdForProfileId();
```

**Obj-C:**

```cpp
_bc->getRelayService()->getNetIdForProfileId();
```

**Java:**

```cpp
_bc->getRelayService()->getNetIdForProfileId();
```

**JavaScript:**

```javascript
_bc.relay.getNetIdForProfileId();
```

**Dart:**

```dart
var profileId = "pppppp";
​
int netId = _bc.relayService.getNetIdForProfileId(profileId);
```

**Roblox:**

```lua
local profileId = "pppppp"

local netId = _bc.relay:getNetIdForProfileId(profileId)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local profileId = "aaa-bbb-ccc-ddd"

local netId = _bc.relay:getNetIdForProfileId(profileId)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/getownercxid.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/getownercxid -->

# GetOwnerCxId

Get the lobby's owner Connection Id.

## Usage

**C#:**

```csharp
_bc.RelayService.GetOwnerCxId();
```

**C++:**

```cpp
_bc->getRelayService()->getOwnerCxId();
```

**Obj-C:**

```cpp
_bc->getRelayService()->getOwnerCxId();
```

**Java:**

```cpp
_bc->getRelayService()->getOwnerCxId();
```

**JavaScript:**

```javascript
_bc.relay.getOwnerCxId();
```

**Dart:**

```dart
String cxId = _bc.relayService.getOwnerCxId();
```

**Roblox:**

```lua
local cxId = _bc.relay:getOwnerCxId()
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local ownerCxId = _bc.relay:getOwnerCxId()
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/getownerprofileid.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/getownerprofileid -->

# GetOwnerProfileId

Get the lobby's owner profile Id.

## Usage

**C#:**

```csharp
_bc.RelayService.GetOwnerProfileId();
```

**C++:**

```cpp
_bc->getRelayService()->getOwnerProfileId();
```

**Obj-C:**

```cpp
_bc->getRelayService()->getOwnerProfileId();
```

**Java:**

```cpp
_bc->getRelayService()->getOwnerProfileId();
```

**JavaScript:**

```javascript
_bc.relay.getOwnerProfileId();
```

**Dart:**

```dart
String cxId = _bc.relayService.getOwnerProfileId();
```

**Roblox:**

```lua
local cxId = _bc.relay:getOwnerProfileId()
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local ownerProfileId = _bc.relay:getOwnerProfileId()
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/getping.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/getping -->

# GetPing

Get the current ping for our user. Note: Pings are not distributed among other members. Your game will have to bundle it inside a packet and distribute to other peers.

## Usage

**C#:**

```csharp
_bc.RelayService.GetPing();
```

**C++:**

```cpp
_bc->getRelayService()->getPing();
```

**Obj-C:**

```cpp
_bc->getRelayService()->getPing();
```

**Java:**

```cpp
_bc->getRelayService()->getPing();
```

**JavaScript:**

```javascript
_bc.relay.getPing();
```

**Dart:**

```dart
int pingTime = _bc.relayService.getPing();
```

**Roblox:**

```lua
local pingTime = _bc.relay:getPing()
```

**GDScript:**

```gdscript
var result = await _bc.relay_service.get_ping()

if result.status == 200:
	print("Success")
else:
	print("Failed: %s" % result.status_message)
```

**Lua:**

```lua
local ping = _bc.relay:getPing() -- milliseconds; 999 until the first ping returns
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/getprofileidfornetid.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/getprofileidfornetid -->

# GetProfileIdForNetId

Returns the profileId associated with a netId.

## Usage

**C#:**

```csharp
_bc.RelayService.GetProfileIdForNetId();
```

**C++:**

```cpp
_bc->getRelayService()->getProfileIdForNetId();
```

**Obj-C:**

```cpp
_bc->getRelayService()->getProfileIdForNetId();
```

**Java:**

```cpp
_bc->getRelayService()->getProfileIdForNetId();
```

**JavaScript:**

```javascript
_bc.relay.getProfileIdForNetId();
```

**Dart:**

```dart
int aNetId = 2;
​
String profileId = _bc.relayService.getProfileIdForNetId(aNetId);
```

**Roblox:**

```lua
local aNetId = 2

local profileId = _bc.relay:getProfileIdForNetId(aNetId)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local netId = 1

local profileId = _bc.relay:getProfileIdForNetId(netId)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/index.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay -->

# Relay

### Generic Relay Server

brainCloud Relay Server is updated to a new Version 2 Protocol in our 4.5.6 release -- which are more reliable, more feature-rich, and faster to launch than our original Relay Servers.

### Purpose

The brainCloud relay server's only purpose is to relay packet data between peer. It is not meant to be an authoritative server, except for the owner migration part.

It is designed to handle clients from various connection types: UDP, TCP or WS. So if I client plays in a webgl version of a game, using WS, he can communicate with a client that plays in UDP on desktop.

The maximum number of players supported by the relay server is 40. But it is highly recommended to keep it low, around 8 players. Peer to Peer generates a lot of traffic.

### Packets

A client that wishes to talk to the relay server is required to follow the brainCloud Relay-Server (BCRS) base protocol.

All the integer values in the following tables are unsigned and in network byte order (Big Endian).

![Relay-Server Packets](@site/docs/img/api-img/packets_5_5_0.png)

#### Ping

Pings will be immediately responded by PONG. The client uses this to calculate their ping. Should send frequently, like every second or so. It is important to pass valid previous ping number because this is used to guess the next best lobby owner, should the original owner leave the game.

The first PING sent should be accompanied with a round trip time (RTT) of 999ms. A common mistake would be to send zero first. The server will use the lowest value to transfer ownership. Someone that just joined should initialize high.

If the PING or PONG packets are dropped, make sure to mark your RTT value in the next PING as high as possible, or 999, instead of the previously known RTT. That is a packet drop, and it should hurt the player's ping.

#### RSMG Acknowledge

This is only used by UDP connections. If a Relay-Server Message (RSMG) is sent to the client, it should be responded with an RSMG Ack. Including the packet id that was sent in the original message. RSMG packets need to be reliable. The Relay-Server will resend those every 200ms until acknowledged.

#### Connection request

brainCloud gave the information about the lobby to the relay server. So it knows who should connect, and each client was given a passcode to use to connect. This should be the first packet sent. A UDP client needs to resend that until a confirmation is received that they are connected. A subsequent connection request will just be ignored if already connected. Re-transmission doesn't need to be high frequency. A suitable interval could be 500ms.

#### Disconnection

This is a clean way to disconnect from the server. If possible, clients should always send this to properly leave a game. Of course, if a game crashes or the browser's tab is killed, it can't do this. There is a timeout in place for those situations.

#### Relay-Server Messages (RSMG)

The relay server will sometimes communicate important system messages to the clients. Those are in json string format. Relay server will keep resending that packet to UDP clients every 200 milliseconds until client acknowledge.

#### Owner migration

If the owner left or never connected in a timely manner, the relay-server will migrate the role to the next member with the best ping. If no one else is currently connected yet, it will be transferred to the next member in the lobby members' list. This last scenario can only occur if the owner connected first, then quickly disconnected. Leaving only unconnected lobby members.

#### End Match

Normal procedure for match termination is to wait for all the participants to disconnect before terminating the instance. This is insufficient however in the case of long-lived lobbies because when a client disconnects from an instance associated with a long-running lobby we send a notification to the brainCloud API servers that said client has prematurely left and the API servers will remove them from any lobbies they are currently a member of. This is not ideal for a long-lived lobby since the clients are meant to stay in it even after the relay server instance has terminated. For this scenario, in release 4.14.0 we have introduced a new END_MATCH message that the instance owner can use to signal that the match is over and can be safely terminated leaving all the clients joined to the lobby instance.

#### UDP Reliables

-   1 bit to specify if the packet is reliable.
-   1 bit to specify if the packet should be in order.
-   2 bit for channel id. 0-3.

The combination of those 4 bits creates what we call a channel idx. Each combination of reliable/ordered, times the 4 channels gives us 16 channels total.

Channels are used to define retransmission speed of reliable packets. Also, each channel will have its own retransmission queue. Packet Ids are unique within a channel only. You can receive/send a packet with id=133 on channel 0, and also another one with the same id=133 but on channel 1.

-   **Channel 0**: fastest retransmission rate (Use for things like bullets)
-   **Channel 1**: fastest retransmission rate (Same, but offer the separated channel. So a dropped bullet packet, for example, wouldn't block something else important.)
-   **Channel 2**: medium retransmission rate (Game events that are important, but not crucial. Like player picked up a gun)
-   **Channel 3**: slow retransmission rate (Use for things like chat messages)

Channel is irrelevant for unreliable packets. Ordering is still relevant in that case, but it just means if a packet arrives out of order, it will be dropped.

### Useful Constants

For anyone implementing the protocol, here are the internally defined constants that will be useful:

```
static const auto MAX_RESEND_INTERVAL = 500ms;
static const auto CHANNEL_HIGH_PRIORITY_1      = 0;
static const auto CHANNEL_HIGH_PRIORITY_2      = 1;
static const auto CHANNEL_NORMAL_PRIORITY      = 2;
static const auto CHANNEL_LOW_PRIORITY         = 3;
static const int      MIN_PACKET_SIZE   = 3;
static const int      MAX_PACKET_SIZE   = 1024;
static const uint8_t  MAX_PLAYERS       = 40;
static const uint8_t  INVALID_NET_ID    = MAX_PLAYERS;
static const uint64_t ALL_PLAYERS_MASK  = 0xFFFFFFFFFFFFFFFF;
// Messages send from Client to Relay-Server
static const uint8_t CL2RS_CONNECT      = 0;
static const uint8_t CL2RS_DISCONNECT   = 1;
static const uint8_t CL2RS_RELAY        = 2;
static const uint8_t CL2RS_ACK          = 3;
static const uint8_t CL2RS_PING         = 4;
static const uint8_t CL2RS_RSMG_ACK     = 5;
static const uint8_t CL2RS_END_MATCH    = 6;
// Messages sent from Relay-Server to Client
static const uint8_t RS2CL_RSMG         = 0;
static const uint8_t RS2CL_DISCONNECT   = 1; // CL2RS_DISCONNECT
static const uint8_t RS2CL_RELAY        = 2; // CL2RS_RELAY
static const uint8_t RS2CL_ACK          = 3; // CL2RS_ACK
static const uint8_t RS2CL_PONG         = 4; // CL2RS_PING
static const int ACK_ID_BYTES_SIZE = 8;
```

> **Info:** We've slightly modified the relay server behaviour when a player disconnects in protocol version v3. We now send the leaver a DISCONNECT (i.e. RS2CL_DISCONNECT) message and everybody else gets a SYSTEM DISCONNECT (i.e. RS2CL_RSMG) message. In v2, everybody got the 2nd one (i.e. RS2CL_RSMG).

And here are the channel resend intervals:

```
static const Duration RELIABLE_RESEND_INTERVALS[] = {
    50ms, 50ms, // High priority 1 and 2
    150ms,      // Normal priority
    500ms       // Low priority
};
static const auto RELIABLE_CHANNEL_HIGH_PRIORITY_1      = 0;
static const auto RELIABLE_CHANNEL_HIGH_PRIORITY_2      = 1;
static const auto RELIABLE_CHANNEL_NORMAL_PRIORITY      = 2;
static const auto RELIABLE_CHANNEL_LOW_PRIORITY         = 3;
```

### Resend Interval Rate

For each reliable packets, the resend rate slows down by 25% each time. This might be tweaked later. So for channel 1, resend at 50ms interface, it will go like this until timeout (10sec):

| interval | total time            | frequency |
| -------- | --------------------- | --------- |
| 50ms     | 0.1s                  | 20        |
| 62ms     | 0.1s                  | 16        |
| 77ms     | 0.2s                  | 13        |
| 96ms     | 0.3s                  | 10        |
| 120ms    | 0.4s                  | 8         |
| 150ms    | 0.5s                  | 7         |
| 187ms    | 0.7s                  | 5         |
| 233ms    | 1.0s                  | 4         |
| 291ms    | 1.3s                  | 3         |
| 363ms    | 1.6s                  | 3         |
| 453ms    | 2.0s                  | 2         |
| 500ms    | 2.5s                  | 2         |
| 500ms    | 3.0s                  | 2         |
| 500ms    | 3.5s                  | 2         |
| 500ms    | 4.0s                  | 2         |
| 500ms    | 4.5s                  | 2         |
| 500ms    | 5.0s                  | 2         |
| 500ms    | 5.5s                  | 2         |
| 500ms    | 6.0s                  | 2         |
| 500ms    | 6.5s                  | 2         |
| 500ms    | 7.0s                  | 2         |
| 500ms    | 7.5s                  | 2         |
| 500ms    | 8.0s                  | 2         |
| 500ms    | 8.5s                  | 2         |
| 500ms    | 9.0s                  | 2         |
| 500ms    | 9.5s                  | 2         |
| 500ms    | 10.0s                 | 2         |
| timeout  | too many packets lost |

### Custom Environment Variables

The following environment variables are used by the relay server which can be configured via Relay server settings page in the dashboard.

-   **PACKET_LOG_ENABLED**: Logs packets sent/received. Shouldn't be enabled for production (very spammy). Defaults to false.
-   **MAX_PLAYERS**: Maximum number of players allowed to connect to the server. Defaults to 40.
-   **ALLOW_REJOIN_BY_PROFILE_ID**: Allows players to reconnect to the server instance if their connection drops (even if they have a new RTT connection as well). Only applies for short-lived lobbies (i.e. where "Disband on start" is true). Defaults to false.
-   **CONNECTION_TIMEOUT**: Amount of time in seconds that a player is allowed to be connected to the server without sending a packet before being kicked. Defaults to 10 secs.
-   **MEMBER_TIMEOUT**: Amount of time to wait in seconds for a player to connect to the server before assuming they aren't coming at all. Defaults to 30 secs.
-   **END_MATCH_TIMEOUT**: Amount of time in seconds to stay up before exiting after receiving the END_MATCH packet. Defaults to 2 secs.
-   **PACKET_LOG_ENABLED_WITH_MD5**: Allows for an MD5 hash logging of incoming and outgoing relay packet payloads.
-   **PAYLOAD_LOG_AS_HEX**: Logs the incoming packet payload as a hex dump rather than an ASCII string.

> **Info:** All the timeout settings are in seconds.

```json
{
    "PACKET_LOG_ENABLED": "true",
    "CONNECTION_TIMEOUT": "240",
    "MEMBER_TIMEOUT": "120",
    "END_MATCH_TIMEOUT": "600",
    "MAX_PLAYERS": "40",
    "ALLOW_REJOIN_BY_PROFILE_ID": "true",
    "PACKET_LOG_ENABLED_WITH_MD5": "true",
    "PAYLOAD_LOG_AS_HEX": "true"
}
```

> **Info:** Note: brainCloud will pass these environment variables by default for any room/relay server it spins up. Below is an example list of environment variables from a launched server.
> 
> ```js
> // passed by default from brainCloud
> APP_ID = 13469
> CONTAINER_EXPOSED_PORTS = 7777/tcp,7777/udp
> EXTERNAL_IP = 3.99.186.192
> EXTERNAL_PORTS = 9001/tcp,9001/udp
> HOSTNAME = 029ec2d7bc98
> LOBBY_ID = 13469:CustomGame:15
> SERVER_NAME = CMSU
> SERVER_HOST = api.braincloudservers.com
> SERVER_PORT = 443
> SERVER_SECRET = 99ef5e85-9a99-4140-8b0d-292b4b13807d
> 
> // from server itself
> HOME = /root
> PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
> 
> // from brainCloud server settings of portal server page
> PACKET_LOG_ENABLED = true
> CONNECTION_TIMEOUT = 240
> ```
> 

### Relay Flow

![Relay Flow](@site/docs/img/api-img/relay_flow.png)

### Client Send Implementation

![Client Send Implementation](@site/docs/img/api-img/client_implementation.png)

### Client Receive Implementation

![Client Receive Implementation](@site/docs/img/api-img/client_receive_implementation.png)

### Exit Codes

The following table describes the known exit codes for the relay server.

| Code | Name                       | Description                                                        |
| ---- | -------------------------- | ------------------------------------------------------------------ |
| 0    | Success                    | Exited cleanly                                                     |
| 1    | GameLiftInitFailed         | Failed to initialize GameLift (GameLift only)                      |
| 2    | I3DInitFailed              | Failed to initialize i3D / OneServer SDK (i3D only)                |
| 3    | MissingRequiredSettings    | Missing expected environment variables                             |
| 4    | S2SInitFailed              | Failed to initialize S2S context                                   |
| 5    | MissingLobbyConfig         | Missing expected lobby instance configuration                      |
| 6    | LobbyConfigRetrievalFailed | Failed to retrieve lobby instance configuration                    |
| 7    | RoomFromLobbyFailed        | Failed to process lobby instance configuration                     |
| 8    | WebSocketListenerFailed    | Failed to initialize websocket server                              |
| 9    | TCPListenerFailed          | Failed to initialize TCP server                                    |
| 10   | UDPListenerFailed          | Failed to initialize UDP server                                    |
| 11   | NoPlayersConnected         | No players connected before MEMBER_TIMEOUT is reached              |
| 12   | RTTInitFailed              | Failed to initialize RTT (required for pre-ready launch)           |
| 13   | PreReadyLaunchError        | Error while waiting for lobby 'starting' state (pre-ready launch)  |
| 14   | GameLiftProcessReadyFailed | Failed to call GameLift ProcessReady (GameLift only)               |
| 15   | I3DNotReady                | i3D / OneServer failed to reach ready state (i3D only)             |
| 16   | I3DAllocationFailed        | Failed to receive allocation from i3D platform (i3D only)          |
| 17   | RoomFromContextFailed      | Failed to process brainCloud context configuration                 |
| 18   | PreReadyLaunchTimeout      | Timeout waiting for lobby 'starting' state (pre-ready launch)      |

### API Summary

### Relay

-   [Connect](/api/capi/relay/connect) - Connect to relay server.
-   [Disconnect](/api/capi/relay/disconnect) - Disconnect from the relay server.
-   [IsConnected](/api/capi/relay/isconnected) - Returns whether or not we have a successful connection with the relay server.
-   [GetPing](/api/capi/relay/getping) - Get the current ping for our user.
-   [SetPingInterval](/api/capi/relay/setpinginterval) - Set the ping interval. Ping allows to keep the connection alive, but also inform the player of his current ping.
-   [GetOwnerProfileId](/api/capi/relay/getownerprofileid) - Get the lobby's owner profile Id.
-   [GetOwnerCxId](/api/capi/relay/getownercxid) - Get the lobby's owner Connection Id.
-   [GetNetIdForProfileId](/api/capi/relay/getnetidforprofileid) - Returns the netId associated with a profileId.
-   [GetCxIdForNetId](/api/capi/relay/getcxidfornetid) - Returns the connection Id associated with a netId.
-   [GetNetIdForCxId](/api/capi/relay/getnetidforcxid) - Returns the netId associated with a connection Id.
-   [Send](/api/capi/relay/send) - Send a packet to peer(s).
-   [SendToPlayers](/api/capi/relay/sendtoplayers) - Send a packet to any players by using a mask.
-   [SendToAll](/api/capi/relay/sendtoall) - Send a packet to all except yourself.
-   [EndMatch](/api/capi/relay/endmatch) - Terminate the match instance by the owner.

### Callbacks

-   [RegisterRelayCallback](/api/capi/relay/registerrelaycallback) - Register callback for relay messages coming from peers.
-   [DeregisterRelayCallback](/api/capi/relay/deregisterrelaycallback) - Deregisters callback for relay messages coming from peers.
-   [RegisterSystemCallback](/api/capi/relay/registersystemcallback) - Register callback for RelayServer system messages.
-   [DeregisterSystemCallback](/api/capi/relay/deregistersystemcallback) - Deregister callback for RelayServer system messages.


---

<!-- source: docs/api/2_capi/relay/isconnected.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/isconnected -->

# IsConnected

Returns whether or not we have a successful connection with the relay server.

## Usage

**C#:**

```csharp
_bc.RelayService.IsConnected();
```

**C++:**

```cpp
_bc->getRelayService()->isConnected();
```

**Obj-C:**

```cpp
_bc->getRelayService()->isConnected();
```

**Java:**

```cpp
_bc->getRelayService()->isConnected();
```

**JavaScript:**

```javascript
_bc.relay.isConnected();
```

**Dart:**

```dart
bool connected = _bc.relayService.isConnected();
```

**Roblox:**

```lua
local connected = _bc.relay:isConnected()
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local connected = _bc.relay:isConnected()
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/registerrelaycallback.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/registerrelaycallback -->

# RegisterRelayCallback

Register callback for relay messages coming from peers.

## Usage

**C#:**

```csharp
//For the client library version 4.5.6, it now includes a netId parameter.
static void relayCallback(short netId, byte[] data)
{
    string message = Encoding.ASCII.GetString(data, 0, data.Length);
    Console.WriteLine("netId: " + netId);
    Console.WriteLine("relayCallback: " + message);
}

//For the client library version 4.5.5 and older, it only has one data parameter.
static void relayCallback(byte[] data)
{
    string message = Encoding.ASCII.GetString(data, 0, data.Length);
    Console.WriteLine("relayCallback: " + message);
}
_bc.RelayService.RegisterRelayCallback(relayCallback);
```

**C++:**

```cpp
_bc->getRelayService()->RegisterRelayCallback(this);
```

**Obj-C:**

```cpp
_bc->getRelayService()->RegisterRelayCallback(this);
```

**Java:**

```cpp
_bc->getRelayService()->RegisterRelayCallback(this);
```

**JavaScript:**

```javascript
_bc.relay.RegisterRelayCallback(result =>
{
    var status = result.status;
    console.log(status + " : " + JSON.stringify(result, null, 2));
});
```

**Dart:**

```dart
 void relayCallback(int netId, Uint8List data) {
   // Your code
 }
​
_bc.relayService.RegisterRelayCallback(relayCallback);
```

**Roblox:**

```lua
local relayCallback = function(jsonResponse)
    -- Your code
end

_bc.relay:registerRelayCallback(relayCallback)
```

**GDScript:**

```gdscript
var result = await _bc.relay_service.register_relay_callback(relayCallback)

if result.status == 200:
	print("Success")
else:
	print("Failed: %s" % result.status_message)
```

**Lua:**

```lua
local relayCallback = function(netId, data)
    print("From " .. tostring(netId) .. ": " .. data)
end

_bc.relay:registerRelayCallback(relayCallback)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/registersystemcallback.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/registersystemcallback -->

# RegisterSystemCallback

Register callback for RelayServer system messages.

## Usage

**C#:**

```csharp
RSDataCallback rsDataCallback = (response) =>
{
    Debug.Log(string.Format("Success | {0}", response));
};

_bc.RelayService.RegisterSystemCallback(rsDataCallback);
```

**C++:**

```cpp
_bc->getRelayService()->registerSystemCallback(this);
```

**Obj-C:**

```cpp
_bc->getRelayService()->registerSystemCallback(this);
```

**Java:**

```cpp
_bc->getRelayService()->registerSystemCallback(this);
```

**JavaScript:**

```javascript
_bc.relay.registerSystemCallback(result =>
{
    var status = result.status;
    console.log(status + " : " + JSON.stringify(result, null, 2));
});
```

**Dart:**

```dart
 void relayCallback(int netId, Uint8List data) {
   // Your code
 }
​
_bc.relayService.registerSystemCallback(relayCallback);

if (result.statusCode == 200) {
    print("Success");
} else {
    print("Failed ${result.error['status_message'] ?? result.error}");
}
```

**Roblox:**

```lua
local relayCallback = function(jsonResponse)
    -- Your code
end

_bc.relay:registerSystemCallback(relayCallback)
```

**GDScript:**

```gdscript
var result = await _bc.relay_service.register_system_callback(relayCallback)

if result.status == 200:
	print("Success")
else:
	print("Failed: %s" % result.status_message)
```

**Lua:**

```lua
-- json.op is CONNECT, NET_ID, DISCONNECT or MIGRATE_OWNER
local systemCallback = function(json)
    print(json.op, json.profileId)
end

_bc.relay:registerSystemCallback(systemCallback)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/send.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/send -->

# Send

Send a packet to peer(s).

## Method Parameters

| Parameter | Description                                                                                               |
| --------- | --------------------------------------------------------------------------------------------------------- |
| data      | Byte array for the data to send                                                                           |
| size      | Size of data in bytes                                                                                     |
| toNetId   | The net id to send to, TO_ALL_PLAYERS to relay to all                                                     |
| reliable  | Send this reliably or not                                                                                 |
| ordered   | Received this ordered or not                                                                              |
| channel   | One of: (CHANNEL_HIGH_PRIORITY_1, CHANNEL_HIGH_PRIORITY_2, CHANNEL_NORMAL_PRIORITY, CHANNEL_LOW_PRIORITY) |

## Usage

**C#:**

```csharp
RSDataCallback rsDataCallback = (response) =>
{
    Debug.Log(string.Format("Success | {0}", response));
};

_bc.RelayService.Send(data, size, toNetId, reliable, ordered, channel);
```

**C++:**

```cpp
_bc->getRelayService()->send(const uint8_t* in_data, int in_size, uint64_t toNetId, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Obj-C:**

```cpp
_bc->getRelayService()->send(const uint8_t* in_data, int in_size, uint64_t toNetId, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Java:**

```cpp
_bc->getRelayService()->send(const uint8_t* in_data, int in_size, uint64_t toNetId, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**JavaScript:**

```javascript
_bc.relay.send(const uint8_t* in_data, int in_size, uint64_t toNetId, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Dart:**

```dart
int aNetId = 2;
Uint8List bytes = utf8.encode("Some Data here");
​
_bc.relayService.send(bytes, aNetId,
          reliable: true,
          ordered: true,
          channel: BrainCloudRelay.channelHighPriority_1);
```

**Roblox:**

```lua
local data = "Hello"
local toNetId = 1
local reliable = true
local ordered = true
local channel = _bc.relay.CHANNEL_HIGH_PRIORITY_1

_bc.relay:send(data, toNetId, reliable, ordered, channel)
```

**GDScript:**

```gdscript
var a_net_id = 2
var bytes = utf8.encode("Some Data here")

var result = await _bc.relay_service.send(true, true, BrainCloudRelay.channelHighPriority_1)

if result.status == 200:
	print("Success")
else:
	print("Failed: %s" % result.status_message)
```

**Lua:**

```lua
local data = "Hello"
local toNetId = 1
local reliable = true
local ordered = true
local channel = _bc.relay.CHANNEL_HIGH_PRIORITY_1

_bc.relay:send(data, toNetId, reliable, ordered, channel)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/sendtoall.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/sendtoall -->

# SendToAll

Send a packet to all except yourself.

## Method Parameters

| Parameter | Description                                                                                               |
| --------- | --------------------------------------------------------------------------------------------------------- |
| data      | Byte array for the data to send                                                                           |
| size      | Size of data in bytes                                                                                     |
| reliable  | Send this reliably or not                                                                                 |
| ordered   | Received this ordered or not                                                                              |
| channel   | One of: (CHANNEL_HIGH_PRIORITY_1, CHANNEL_HIGH_PRIORITY_2, CHANNEL_NORMAL_PRIORITY, CHANNEL_LOW_PRIORITY) |

## Usage

**C#:**

```csharp
RSDataCallback rsDataCallback = (response) =>
{
    Debug.Log(string.Format("Success | {0}", response));
};

_bc.RelayService.SendToAll(data, size, reliable, ordered, channel);
```

**C++:**

```cpp
_bc->getRelayService()->sendToAll(const uint8_t* in_data, int in_size, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Obj-C:**

```cpp
_bc->getRelayService()->sendToAll(const uint8_t* in_data, int in_size, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Java:**

```cpp
_bc->getRelayService()->sendToAll(const uint8_t* in_data, int in_size, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**JavaScript:**

```javascript
_bc.relay.sendToAll(const uint8_t* in_data, int in_size, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Dart:**

```dart
int aNetId = 2;
Uint8List bytes = utf8.encode("Some Data here");
​
_bc.relayService.sendToAll(bytes,
          reliable: true,
          ordered: true,
          channel: BrainCloudRelay.channelHighPriority_1);
```

**Roblox:**

```lua
local data = "Hello"
local reliable = true
local ordered = true
local channel = _bc.relay.CHANNEL_HIGH_PRIORITY_1

_bc.relay:sendToAll(data, reliable, ordered, channel)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local data = "Hello"
local reliable = true
local ordered = true
local channel = _bc.relay.CHANNEL_HIGH_PRIORITY_1

_bc.relay:sendToAll(data, reliable, ordered, channel)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/sendtoplayers.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/sendtoplayers -->

# SendToPlayers

Send a packet to any players by using a mask.

## Method Parameters

| Parameter  | Description                                                                                                                                                                                                                                                                           |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| data       | Byte array for the data to send                                                                                                                                                                                                                                                       |
| size       | Size of data in bytes                                                                                                                                                                                                                                                                 |
| playerMask | Mask of the players to send to. 0001 = netId 0, 0010 = netId 1, etc. If you pass ALL_PLAYER_MASK you will be included and you will get an echo for your message. Use sendToAll instead, you will be filtered out. You can manually filter out by : `ALL_PLAYER_MASK &= ~(1 &lt;&lt; myNetId)` |
| reliable   | Send this reliably or not                                                                                                                                                                                                                                                             |
| ordered    | Received this ordered or not                                                                                                                                                                                                                                                          |
| channel    | One of: (CHANNEL_HIGH_PRIORITY_1, CHANNEL_HIGH_PRIORITY_2, CHANNEL_NORMAL_PRIORITY, CHANNEL_LOW_PRIORITY)                                                                                                                                                                             |

## Usage

**C#:**

```csharp
RSDataCallback rsDataCallback = (response) =>
{
    Debug.Log(string.Format("Success | {0}", response));
};

_bc.RelayService.SendToPlayers(data, size, playerMask, reliable, ordered, channel);
```

**C++:**

```cpp
_bc->getRelayService()->sendToPlayers(const uint8_t* in_data, int in_size, uint64_t in_playerMask, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Obj-C:**

```cpp
_bc->getRelayService()->sendToPlayers(const uint8_t* in_data, int in_size, uint64_t in_playerMask, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Java:**

```cpp
_bc->getRelayService()->sendToPlayers(const uint8_t* in_data, int in_size, uint64_t in_playerMask, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**JavaScript:**

```javascript
_bc.relay.sendToPlayers(const uint8_t* in_data, int in_size, uint64_t in_playerMask, bool in_reliable, bool in_ordered, eRelayChannel in_channel);
```

**Dart:**

```dart
Uint8List bytes = utf8.encode("Some Data here");
int mask = 0;
// Send only to NetID 0, 2 and 5
for (var netId in [0,2,5]) {
  mask += (1 << netId);
}
​
_bc.relayService.sendToPlayers(bytes, playerMask:mask,
          reliable: true,
          ordered: true,
          channel: BrainCloudRelay.channelLowPriority);
```

**Roblox:**

```lua
local data = "Hello"
local playerMask = 2 ^ 1 + 2 ^ 3 -- one bit per netId: players 1 and 3
local reliable = true
local ordered = true
local channel = _bc.relay.CHANNEL_HIGH_PRIORITY_1

_bc.relay:sendToPlayers(data, playerMask, reliable, ordered, channel)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local data = "Hello"
local playerMask = 2 ^ 1 + 2 ^ 3 -- one bit per netId: players 1 and 3
local reliable = true
local ordered = true
local channel = _bc.relay.CHANNEL_HIGH_PRIORITY_1

_bc.relay:sendToPlayers(data, playerMask, reliable, ordered, channel)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```


---

<!-- source: docs/api/2_capi/relay/setpinginterval.md -->
<!-- url: https://docs-internal.braincloudservers.com/api/capi/relay/setpinginterval -->

# SetPingInterval

Set the ping interval.

## Method Parameters

| Parameter | Description              |
| --------- | ------------------------ |
| interval  | Seconds inbetween pings. |

## Usage

**C#:**

```csharp
float interval = 10;
_bc.RelayService.SetPingInterval(interval);
```

**C++:**

```cpp
_bc->getRelayService()->SetPingInterval(10);
```

**Obj-C:**

```cpp
_bc->getRelayService()->SetPingInterval(10);
```

**Java:**

```cpp
_bc->getRelayService()->SetPingInterval(10);
```

**JavaScript:**

```javascript
_bc.relay.setPingInterval(10);
```

**Dart:**

```dart
int interval = 10;
​
_bc.relayService.setPingInterval(interval);
```

**Roblox:**

```lua
local interval = 10

_bc.relay:setPingInterval(interval)
```

**GDScript:**

```gdscript
N/A
```

**Lua:**

```lua
local seconds = 10

_bc.relay:setPingInterval(seconds)
```

**Cloud Code:**

```cfscript
// N/A
```

**Raw:**

```r
// N/A
```
