Connecting¶
After starting MafiaNet, you can connect to remote systems.
Initiating a Connection¶
ConnectionAttemptResult Connect(
const char *host,
unsigned short remotePort,
const char *passwordData,
int passwordDataLength,
PublicKey *publicKey = 0,
unsigned connectionSocketIndex = 0,
unsigned sendConnectionAttemptCount = 6,
unsigned timeBetweenSendConnectionAttemptsMS = 1000,
TimeMS timeoutTime = 0
);
Basic usage:
MafiaNet::ConnectionAttemptResult result = peer->Connect(
"192.168.1.100", // IP address or hostname
60000, // Port
nullptr, // No password
0 // Password length
);
if (result != MafiaNet::CONNECTION_ATTEMPT_STARTED) {
printf("Failed to initiate connection: %d\n", result);
}
Connection Parameters¶
host¶
IP address (e.g., “192.168.1.100”) or hostname (e.g., “game.example.com”).
remotePort¶
The port the remote system is listening on (set in their Startup() call).
passwordData / passwordDataLength¶
Optional password for authentication:
const char* password = "secretpassword";
peer->Connect("192.168.1.100", 60000, password, strlen(password));
The remote system must call SetIncomingPassword() with the same password.
sendConnectionAttemptCount / timeBetweenSendConnectionAttemptsMS¶
Control retry behavior. Default: 6 attempts, 1 second apart.
timeoutTime¶
How long to wait for connection before giving up (milliseconds). 0 = use default.
Handling Connection Results¶
Check for connection packets in your receive loop:
MafiaNet::Packet* packet;
for (packet = peer->Receive(); packet;
peer->DeallocatePacket(packet), packet = peer->Receive()) {
switch (packet->data[0]) {
case ID_CONNECTION_REQUEST_ACCEPTED:
printf("Connected to %s\n",
packet->systemAddress.ToString());
break;
case ID_CONNECTION_ATTEMPT_FAILED:
printf("Connection attempt failed\n");
break;
case ID_NO_FREE_INCOMING_CONNECTIONS:
printf("Server is full\n");
break;
case ID_INVALID_PASSWORD:
printf("Wrong password\n");
break;
case ID_ALREADY_CONNECTED:
printf("Already connected to this system\n");
break;
case ID_CONNECTION_BANNED:
printf("Banned from server\n");
break;
}
}
Accepting Connections (Server)¶
To accept incoming connections:
// Must be ≤ maxConnections from Startup()
peer->SetMaximumIncomingConnections(100);
Optionally set a password:
const char* password = "secretpassword";
peer->SetIncomingPassword(password, strlen(password));
Handle new connections:
case ID_NEW_INCOMING_CONNECTION:
printf("New client connected: %s\n",
packet->systemAddress.ToString());
break;
Disconnecting¶
Graceful disconnect:
peer->CloseConnection(systemAddress, true); // true = send notification
The remote system receives ID_DISCONNECTION_NOTIFICATION.
Disconnect with a reason¶
A graceful disconnect can carry an optional payload so the remote peer learns
why it was dropped (for example a kick/ban reason). Pass a BitStream as
the final reasonData argument to CloseConnection; its bytes are appended
right after the ID_DISCONNECTION_NOTIFICATION message ID:
enum KickReason : uint8_t { KR_BANNED, KR_KICKED, KR_SERVER_FULL };
MafiaNet::BitStream reason;
reason.Write((uint8_t)KR_KICKED); // an enum code...
MafiaNet::RakString("Cheating in match #4821") // ...plus an optional custom string
.Serialize(&reason);
peer->CloseConnection(systemAddress, true, 0, MafiaNet::Priority::Low, &reason);
The receiver reads the reason from the notification packet exactly like any
other message body — packet->data + 1 for packet->length - 1 bytes:
case ID_DISCONNECTION_NOTIFICATION:
if (packet->length > 1) {
MafiaNet::BitStream in(packet->data + 1, packet->length - 1, false);
uint8_t code;
MafiaNet::RakString text;
in.Read(code);
in.Deserialize(&text);
// show "Kicked: <text>", "You were banned.", etc.
}
break;
Note
Only graceful disconnects carry a reason. Locally-synthesized
notifications — ID_CONNECTION_LOST and the timeout/dead-connection path
that also surfaces as ID_DISCONNECTION_NOTIFICATION — have no remote
sender and stay payload-less, so always tolerate a zero-length body
(packet->length == 1). Appending bytes after the ID is
wire-backward-compatible: peers that only inspect packet->data[0] are
unaffected, and you can send a single enum byte if you want minimal overhead.
Forceful disconnect (no notification):
peer->CloseConnection(systemAddress, false);
The remote system will eventually get ID_CONNECTION_LOST.
Connection Events Summary¶
Message ID |
Description |
|---|---|
|
Successfully connected (client) |
|
New client connected (server) |
|
Could not connect |
|
Server is full |
|
Wrong password |
|
Clean disconnect |
|
Connection timed out |
|
IP is banned |
Checking Connection State¶
MafiaNet::ConnectionState state = peer->GetConnectionState(systemAddress);
switch (state) {
case MafiaNet::IS_CONNECTED:
// Fully connected
break;
case MafiaNet::IS_CONNECTING:
// Connection in progress
break;
case MafiaNet::IS_DISCONNECTING:
// Disconnecting
break;
case MafiaNet::IS_NOT_CONNECTED:
// Not connected
break;
}
The Session Handshake¶
After the transport connection is established but before either side reports it, MafiaNet
exchanges an opaque application payload in both directions. The connecting peer sends its payload in
ID_SESSION_CONFIG_REQUEST; the accepting peer answers with ID_SESSION_CONFIG.
Neither ID_CONNECTION_REQUEST_ACCEPTED nor ID_NEW_INCOMING_CONNECTION is produced until that
exchange completes. Those packets therefore mean “the remote peer’s session payload is in hand” –
an application cannot observe a connection without its session data, and there is no window in which
it must remember to check.
The payload is opaque to MafiaNet: encode it however the application likes, up to
MAXIMUM_SESSION_CONFIG_SIZE bytes.
Warning
A payload received from a remote peer is untrusted, unauthenticated input – it arrives before any application-level authentication has run. Parse it as defensively as any other packet from an unknown source, and never put secrets in a payload sent from static mode. See Session Handshake Security.
Static payloads¶
The common case needs no application code beyond staging the bytes:
// Server: published to every client that connects
server->SetSessionConfig(configJson.c_str(), (unsigned int)configJson.size());
// Client: sent up with the connection request
client->SetSessionConfig(buildToken.c_str(), (unsigned int)buildToken.size());
Read the remote payload as soon as the connection surfaces:
case ID_CONNECTION_REQUEST_ACCEPTED: {
unsigned int length = 0;
const char *config = client->GetRemoteSessionConfig(packet->guid, &length);
// config is already available here -- that is the point of the handshake
break;
}
Per-client decisions¶
A server that needs to inspect each client before answering turns on interactive mode. The client’s payload arrives first, so the server can refuse without ever having disclosed its own:
server->SetSessionConfigInteractive(true);
case ID_SESSION_CONFIG_REQUEST:
if (BuildTokenMatches(packet->data + 1, packet->length - 1)) {
server->AcceptSession(packet->guid, configJson.c_str(), (unsigned int)configJson.size());
} else {
server->RejectSession(packet->guid, "build mismatch");
}
break;
While the decision is outstanding the connection stays unreported on both sides.
RejectSession() produces ID_CONNECTION_ATTEMPT_FAILED on the client with the reason string at
packet->data + 1, and no connection is ever reported anywhere.
A peer that is never answered is timed out like any other incomplete connection attempt, using the
timeout set by MafiaNet::RakPeerInterface::SetTimeoutTime(). During the exchange GetConnectionState() reports
IS_CONNECTING.
Note
The session handshake changes the wire protocol, so RAKNET_PROTOCOL_VERSION was raised to 7.
Peers built against an older MafiaNet are rejected during the offline connection phase with
ID_INCOMPATIBLE_PROTOCOL_VERSION.
See Also¶
Startup - Starting MafiaNet
Debugging Disconnects - Troubleshooting connection issues