Jump to content

OpenSimulator Internals/Code Map/ROBUST/UserAgentService

From Open Simulator Technical Help

OpenSimulator Internals/Code Map/ROBUST/UserAgentService

[edit]

Overview

[edit]

UserAgentService is the home grid's agent tracking service for HyperGrid. It maintains a traveling agent database, handles outbound HG teleports, authenticates agents at foreign grids, and provides friend status and user info to foreign grids on behalf of local users.

The class comment notes this service exists because HG1.5 clients don't carry private state themselves -- the home service carries it for them. The comment suggests this shouldn't be needed once clients improve.

Source files:

OpenSim/Services/HypergridService/UserAgentService.cs
OpenSim/Services/HypergridService/UserAgentServiceBase.cs

Constructor and Config Loading

[edit]
UserAgentServiceBase(IConfigSource config)

Config is read in two layers; [UserAgentService] overrides [DatabaseService]:

Section Key Default Notes
[DatabaseService] StorageProvider (none) DLL name -- fallback
[DatabaseService] ConnectionString (none) DB connection string -- fallback
[UserAgentService] StorageProvider (inherited) Overrides [DatabaseService]
[UserAgentService] ConnectionString (inherited) Overrides [DatabaseService]
[UserAgentService] Realm hg_traveling_data Table name

Throws if StorageProvider is empty or plugin cannot be loaded. Loaded plugin stored as m_Database (IHGTravelingData).

UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector)

[UserAgentService] section is required -- throws if absent. All static fields initialized once (m_Initialized flag).

friendsConnector argument is always assigned to m_FriendsLocalSimConnector if non-null, even on subsequent instantiations (bypasses the m_Initialized guard).

Services loaded from [UserAgentService]:

Key Interface Required
GridService IGridService Yes -- throws if empty
GridUserService IGridUserService Yes -- throws if empty
GatekeeperService IGatekeeperService Yes -- throws if empty
FriendsService IFriendsService No
PresenceService IPresenceService No
UserAccountService IUserAccountService No

Additional config:

Section Key Default Notes
[UserAgentService] BypassClientVerification false If true, VerifyClient() always returns true
[UserAgentService] LevelOutsideContacts 0 Minimum UserLevel to be visible to foreign grids via GetUUID()
[UserAgentService] ShowUserDetailsInHGProfile true If false, user_flags/user_created/user_title return zeros in GetUserInfo()
[UserAgentService] ForeignTripsAllowed_Level_N (none) Per-level bool: whether users at that level may visit foreign grids
[UserAgentService] AllowExcept_Level_N (none) Per-level comma-separated grid URLs exempt from ForeignTripsAllowed=true
[UserAgentService] DisallowExcept_Level_N (none) Per-level comma-separated grid URLs exempt from ForeignTripsAllowed=false
[Startup]/[Hypergrid]/[UserAgentService] GatekeeperURI (none) This grid's external URL; also tries ExternalName in [UserAgentService] then [GatekeeperService]

GatekeeperURI is resolved via DNS at startup. m_MyExternalIP stores the resolved IP for NAT detection in VerifyClient(). Throws if URI cannot be parsed or hostname cannot be resolved.

m_Database.DeleteOld() is called at the end of constructor to purge stale travel records.


Traveling Agent Database

[edit]

IHGTravelingData (table: hg_traveling_data) stores one row per active HG session:

Field Notes
SessionID Agent session UUID
UserID Agent UUID
GridExternalName Grid URL where the agent currently is
ServiceToken The ServiceSessionID generated for this hop (used by VerifyAgent)
ClientIPAddress Client IP as seen at login time

TravelingAgentInfo is an in-memory wrapper over HGTravelingData. Not persisted directly -- StoreTravelInfo() converts it back to HGTravelingData for storage.


GetHomeRegion()

[edit]
public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt)

Looks up GridUserInfo for userID. If HomeRegionID is set, fetches the region from GridService. If that fails or HomeRegionID is zero, falls back to GridService.GetDefaultRegions()[0]. Returns null if nothing found. Default position is (128, 128, 0).


LoginAgentToGrid()

[edit]
public bool LoginAgentToGrid(GridRegion source, AgentCircuitData agentCircuit, GridRegion gatekeeper,
    GridRegion finalDestination, bool fromLogin, out string reason)

Handles outbound HG teleport from this grid to a foreign (or local) grid.

  1. Account check: agent must be a local user (GetUserAccount) -- refuses foreign users with "Forbidden to launch your agents from here"
  2. Foreign trip policy (if destination grid != this grid):
    • Checks m_ForeignTripsAllowed[account.UserLevel] -- if key absent, no restriction
    • Applies AllowExcept/DisallowExcept per-level exceptions (exact URL match, trailing slash normalized)
    • Returns false if not allowed
  3. Builds composite GridRegion: gatekeeper's ServerURI + finalDestination's host/port/name/ID/coordinates
  4. Generates new ServiceSessionID: region.ServerURI + ";" + random UUID
  5. CreateTravelInfo(): stores new HGTravelingData, returns existing record if any
    • If not fromLogin and existing record has a stored IP: overwrites agentCircuit.IPAddress with the stored IP (preserves original client IP across hops)
  6. Launch:
    • If destination is this grid: calls GatekeeperService.LoginAgent() directly (local path)
    • Otherwise: calls GatekeeperConnector.CreateAgent() on the foreign gatekeeper (remote path)
    • TODO comment in source notes QueryAccess is not called on the remote path
  7. On failure: restores old TravelingAgentInfo if it existed, else deletes the session record
  8. On success: stores the new TravelingAgentInfo

LogoutAgent()

[edit]
public void LogoutAgent(UUID userID, UUID sessionID)

Deletes the travel record for sessionID. Calls GridUserService.LoggedOut() using the last known position from GridUserInfo.


IsAgentComingHome()

[edit]
public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName)

Called by GatekeeperService to distinguish a returning local user from a foreign agent with a colliding UUID.

Looks up the travel record for sessionID. Returns true if GridExternalName matches thisGridExternalName (case-insensitive). Returns false if no record exists.


VerifyClient()

[edit]
public bool VerifyClient(UUID sessionID, string reportedIP)

Called by simulators to verify a connecting client is who they claim to be.

If BypassClientVerification = true: always returns true.

Otherwise: fetches travel record, compares reportedIP against stored ClientIPAddress. Also accepts m_MyExternalIP as a match (NAT: client and server share the same external IP).


VerifyAgent()

[edit]
public bool VerifyAgent(UUID sessionID, string token)

Called by GatekeeperService.Authenticate() on the home grid side. Fetches travel record, compares token against stored ServiceToken. Returns false if no record.


GetOnlineFriends()

[edit]
public List<UUID> GetOnlineFriends(UUID foreignUserID, List<string> friends)

Called by a foreign grid to find which local friends of a visiting user are online.

For each UUI in friends:

  • Parses the UUI to extract localUserID and secret
  • Fetches FriendInfo for localUserID
  • Checks that the foreign user is in the friend list (matching by UUID prefix and secret) AND has CanSeeOnline rights

Then calls PresenceService.GetAgents() on the confirmed list. Returns UUIDs of those with active presence records.


GetUserInfo()

[edit]
public Dictionary<string, object> GetUserInfo(UUID userID)

Returns basic user info for display on foreign grids. Always returns user_firstname and user_lastname. If ShowUserDetailsInHGProfile = true: returns actual user_flags, user_created, user_title. If false: returns zeros and empty string.

Returns a dict with result = "fail" if UserAccountService is not configured.


GetServerURLs()

[edit]
public Dictionary<string, object> GetServerURLs(UUID userID)

Returns the ServiceURLs dictionary from the UserAccount record. Returns empty dict if UserAccountService not configured or user not found.


LocateUser()

[edit]
public string LocateUser(UUID userID)

Searches all travel records for userID. Returns the GridExternalName of the first session where the agent is on a foreign grid (not this grid). Returns empty string if not found or only on home grid.


GetUUI()

[edit]
public string GetUUI(UUID userID, UUID targetUserID)

Returns the Universal User Identifier for targetUserID as seen by userID.

First checks local UserAccounts -- returns agentID + ";" + m_GridName + ";" + name.

If not local: searches userID's friend list for a record starting with targetUserID. Strips the secret from the UUI (replaces it with "0") before returning.

Returns empty string if not found.


GetUUID()

[edit]
public UUID GetUUID(string first, string last)

Looks up a local user by name. Returns UUID.Zero if not found or if account.UserLevel < LevelOutsideContacts.


StatusNotification()

[edit]
[Obsolete]
public List<UUID> StatusNotification(List<string> friends, UUID foreignUserID, bool online)

Marked Obsolete. Notifies local friends of a foreign user's online/offline status change. The cross-grid notification path (forwarding to users visiting other grids) is commented out with a note that HG status notifications are "still not implemented." Only the first online local friend is notified; the rest of the loop was truncated.


Notes

[edit]
  • ForeignTripsAllowed is keyed by UserLevel integer -- if a level has no entry, no restriction applies for that level.
  • The remote path in LoginAgentToGrid() skips QueryAccess; a TODO comment in the source acknowledges this.
  • StatusNotification() is marked Obsolete and the cross-grid notification path inside it is commented out.
  • The class comment explicitly calls this service a stopgap for HG1.5 client limitations.

See Also

[edit]