Login & Session

Before a client can do anything, it needs to establish a session with the server. Currently mainstream OpenSimulator servers use xml-rpc to establish the initial connections, though Secondlife servers have moved on to a more modern method.

Throughout the protocol, the method used for logging in is entirely unique.

Collect Login Credentials

To begin the process of logging in, you need to first provide your user with a means of inputting their login credentials. The metaverse protocol requires more than the usual amount of information when establishing sessions.

Though this is all the information you need from the user, this is not all the information you'll need to create a valid LoginRequest XML. This information is collected from the user in the UI and sent to the core as a UIResponse. More information about core and UI communication can be found here.

An example login would look something like this.

let login_data = Login {
    first: "default".to_string(),
    last: "user".to_string(),
    passwd: "password".to_string(),
    start: "home".to_string(),
    channel: "benthic".to_string(),
    agree_to_tos: true,
    read_critical: true,
};
    
Evil Benthic

Start Field

While most of the login struct can be anything, the Start field can only be set with specific values. These can be "home", "last", and coordinates in the format "uri:[region-name]&[x-coord]&[y-coord]&[z-coord]". For example, the string "uri:test&128&128&0" places the user in the center of a region called "test". if the start is not set to one of these options, the server will respond with

Error generating Login Response
which is very difficult to debug.

XML-RPC Login

Now that the login credentials are being sent to the mailbox, it's time for the core to take over and begin the handshake process.

The first thing that must happen is the raw Login data must be converted to XML-RPC that can be sent to the login server. The first step of this is done by creating a new SimulatorLoginProtocol object from the Login UIResponse.
The SimulatorLoginProtocol is a large structure that is used by the server to create a login response. It contains far more fields than just the username and password, and should be populated by the core using the new function in the object.
Now that we have a SimulatorLoginProtocol object, we can serialize that into xml-rpc using the serde-llsd-benthic crate, and send it to the url included in the login. login_to_simulator() is called, which creates an xml-rpc post, sends it to the server, and awaits the response.

Handle LoginResponse

Once the post request is sent, the response is awaited, and the response parsed. The resulting login response is contained in the enum LoginStatus, which can contain both a success and a failure. On success, a LoginResponse object is created, which contains all of the fields necessary for running a full metaverse client.
There are many fields in the LoginResponse object that are unused, or are unknown what their function once was. Only a small subset of the struct is used by the server to establish the session.

first_name

First name of the logged in user. Not necessarily useful, considering the first name should already be known by the client at this point.

last_name

Last name of the logged in user. Also should be known at this point.

agent_id

Agent ID of the user. This will be used globally to differentiate the client's user from other users, and send messages as coming from the user.

session_id

ID of the session. This will be used globally to inform the server about which session messages are being sent from.

sim_ip

IP of the server. Used by the session to establish a UDP connection.

sim_port

The port opened by the server for the core to establish the UDP connection.

seed_capability

The base URL used for retrieving capability urls.
Optional if your client does not support capability endpoints.

Initialize Session

Now that we have the LoginResponse, we have all the information we need to complete the authentication handshake.
The LoginResponse data is used to create a Session object here. This is sent to the mailbox, to set the global values that are required throughout the runtime. The session object is then handled by the mailbox, which opens up another UDP socket which asyncronously listens for events coming from the server, using the sim_ip and sim_port provided by the login response.
There are now three UDP sockets listening on the machine.

Circuit Code

With the session populated, we can begin the circuit code handshake. The Circuit Code is a way of establishing initial contact between the server and the client. This is the first UDP packet that must be sent before any other communication is possible.
This is sent to the mailbox, which handles it as an outgoing packet and sends it to the server via UDP using the URL and socket that were retrieved from the LoginResponse.

RegionHandshake

In response to the circuit code packet, a Region Handshake packet is sent from the server. If this packet is not received, this means the circuitcode was not accepted, or this packet was parsed incorrectly. Check the headers documentation to ensure that you have handled this packet's zerocoded header.

As of right now your avatar is in the child agent state.

Child Agent

  • Can receive objectupdate packets for some attachments
  • Can receive layerdata for environment
  • Can send and receive chat messages
  • Avatar can be seen as present in-world by other players

  • Cannot receive full object data from the environment
  • Cannot move around in the scene
  • Is not considered by the server to be fully present.

Root Agent

  • Considered fully logged in by the server
  • Receives full ObjectUpdate packets
  • Can move around in-world
After receiving this packet, it must be replied to with a RegionHandshakeResponse packet.

RegionHandshakeResponse

After receiving the Region Handshake packet, the viewer must reply with the RegionHandshakeResponse packet. This will promote the agent from a child to a root agent, allowing for full ObjectUpdate packets to be received, and the player to move around.

Establish Ping

After the Circuit Code is sent, metaverse servers will begin sending ping messages, to ensure the client is still active. The StartPingCheck packet will be sent from the server to the client. The server must respond with a CompletePingCheck packet, or else you will be logged out eventually.

When the mailbox receives a ping packet, it automatically responds, which is then used to calculate the latency from the server and the client.
More information about packet handling can be found on the packet handling page.

Complete Agent Movement

The next step of the handshake is the Complete Agent Movement packet. This should be sent when you want your user's avatar to be rendered into the world. At this point you have successfully authenticated with the metaverse server, and your avatar should be rendering in the world!