Direct Service Requests

= Introduction =

In the vast majority of cases, viewer requests are handled by the simulator which then interacts with backend services (asset, inventory, etc.) as appropriate.

However, in the default configuration some of these requests are handled by the viewer interacting with a backend service directly. For instance, on login, the login service passes the viewer a map URL as configured in the MapTileURL section of [LoginService] in Robust.ini. When the viewer requires tiles to display on the main map, it contacts this URL to fetch them. The URL itself is served by the ROBUST service on the public grid port (8002 by default).

There is also scope to handle more requests directly. However, the only good known working example, as detailed here, is one to handle GetTexture requests directly from a service rather than via a simulator. More examples will be added in the future, though with some there are currently some significant security considerations to bear in mind.

= Direct GetTexture capability handling = GetTexture is a client-viewer protocol capability by which clients (viewers) can request textures via HTTP instead of the old UDP based mechanisms.

Normally, OpenSimulator handles this by providing a capability endpoint that resolves to the simulator occuped by the user's avatar. Requests are received by the simulator and the asset retrieved from cache or by a call to the backend asset service as appropriate.

However, we can also configure GetTexture to be handled directly by a service instead via the public grid port. The capability endpoint passed to the viewer then resolves directly to this service instead of the simulator, much like map tiles are provided directly by a service.

This setup will work for both non-Hypergrid and Hypergrid installations (since all required assets are copied into the local asset service when a foreign user enters the simulator and when they rez or otherwise transfer items from their inventory).

Configuration
The first thing to do is to configure the service to provide the GetTexture capability connector. We can do this with the config below.

I'm assuming here that we are running the GetTexture service inside an entirely separate Robust service instance. However, it can be run in a Robust shell that it also handling other services (e.g. the default grid one that handles all services). In thie case, you can leave some sections out as we shall outline below.

Here is an explanation of each section.


 * [Startup] - This is blank and only here to because the Robust service shell currently mandates it. It may not be necessary in the future.  In a shared service shell an existing [Startup] section will be used.
 * [ServiceList] - This triggers the initialization of the GetTexture capability connector. Here, we explicitly specify a port of 8010 though this can be omitted if it is the same as the default 'port' setting in the Network section.  This is the port by which the viewer will be communicating with the GetTextureConnector so it must be accessible to a viewer through your firewall.  You should not be running any private services (e.g. internal asset service) on this port.
 * [Network].port - OpenSimulator will currently always complain if this is not present even if you only have one connector and that explicitly specifies the port you are using (as above). If you are expicitly specifying the GetTextureConnector port then this can be any free port on your server (it will not be used if there are no other services).  If you are running GetTextureConnector in a shared service shell then any existing port setting will suffice.
 * [CapsService].AssetService - This specifies the asset service for GetTextureConnector to initialize from which to fetch textures (which are assets).
 * [DatabaseService] - This contains the settings for the AssetService to access the database. If GetTextureConnector is sharing the robust shell with other services then this very probably already exists.
 * [AssetService] - This section is blank and exists only to stop AssetService fatally complaining. It may disappear as a requirement in the future.

Now, when you startup the Robust shell hosting GetTextureConnector and run the command "show http-handlers" you should see something like the following (for clarity we show the output where GetTextureConnector is the only thing running in the shell).

R.O.B.U.S.T.# show http-handlers Registered HTTP Handlers for server at 0.0.0.0:8010 GET:/CAPS/GetTexture/
 * XMLRPC:
 * HTTP:
 * HTTP (poll):
 * JSONRPC:
 * LLSD:
 * StreamHandlers (1):

This shows that the endpoint /CAPS/GetTexture is now available.

Now we need to configure the simulators to provide viewers with the GetTexture capability that points to the service. In the [ClientStack.LindenCaps] section of OpenSim.ini for each simulator we need to add something like the following.

This overrides the usual "localhost" setting specified in bin/OpenSimDefaults.ini. In thie case, the URL points to a LAN IP (192.168.1.2). But for a public grid, this needs to be a public host that can be reached by all viewers (e.g. services.mygrid.com).

Now, when a viewer logs in it will make GetTexture requests directly to the service, by passing the simulator entirely. If the GetTextureConnnector is running in its own shell, you can check this is happening by running a command such as "show stats httpserver.8010.HttpRequestsServed.

R.O.B.U.S.T.# show stats httpserver.8010.HTTPRequestsServed httpserver.8010.HTTPRequestsServed : 139 requests, 0 requests/s, 0 requests/s

In this case, we can see that the service has now served 139 requests. Unfortunately, it's harder to check if the shell is being shared by multiple services on the same port - we do not currently register stats to show capabilities (though this should change in the future).

Experimental configuration
'''This configuration is extremely experimental and not yet known to fully work. It's being left here for reference purposes.'''

Instead of instantiating an AssetService to take care of GetTexture requests at the service end, we can potentially instantiate an HGAssetBroker instance when Hypergrid is active. At the moment, this is not necessary since assets are being copied into the local asset service when required (and so the vanilla GetTexture configuration above will always find them). However, there may be future experiments with not copying these assets up front and only requesting/caching them on demand. This will also require extra code to correctly transfer the asset if it is permanently required (e.g. because an attachment is rezzed in a region or given to another user).

The configuration below is currently only possible in the 'ghosts' development branch in the OpenSimulator repository, as of commit 0437d44 (post 0.8), although this will soon be in master development code.

The service side configuration for this is as follows. The simulator side configuration is the same as in the normal case.

The changes compared to the non-Hypergrid configuration are as follows.


 * [CapsService].AssetService now instantiates HGAssetBroker from OpenSim.Region.CoreModules.dll rather than AssetService from OpenSim.Services.AssetService.
 * [AssetService] now contains two entries. The LocalGridAssetService entry tells HGAssetBroker which asset service to instantiate and use for home grid asset requests.  The HypergridAssetService entry tells HGAssetBroker which asset service to instantiate and use for requests to foreign asset services.
 * [Modules].AssetServices is the entry required to get HGAssetBroker to run after it has been instantiated. This is necessary because up until very recently, HGAssetBroker was a region module only that was never instantiated by the CapsService.  This requirement may go away in the future.

= Pros and Cons =

Pros
Handling requests directly via a service has the following advantages.

Reduced simulator load
Handling requests directly by the service removes processing load from the simulator itself. This is most relevant to services that handle a high number of requests, such as GetTexture. However, the impact has not yet been properly measured.

Consistent performance
When a request is handled directly by the service, performance in satisfying that request will not potentially vary between simulators operating under different conditions.

Cons
However, it also has the following disadvantages.

All load is on the service
Instead of being spread to some extent between simulators, all service request load is now placed on the single service point (e.g. GetTexture). This is particularly an issue in grids with higher numbers of users and simulators. In the case of GetTexture and any request involving an asset, it's also the case that often these assets would be served from the local simulator cache. However, this problem can be tackled by load balancing requests between multiple service instances, as all services are stateless. Ultimately, one could also use alternative service implementations (e.g. SRAS for the asset service) which are likely considerably more efficient than the built-in ROBUST service implementations. In general, a wealth of knowledge and software already exists for scaling services.

Security
To take GetTexture as an example, if you run the command "show caps list" on the simulator when at least one user is logged in, you will see that the GetTexture capability is now served by a fixed URL rather than one which contains a random component. For example

OpenSim (test)# show caps list Region test: ObjectAdd                             /CAPS/OA/a7dd11fd-5f0c-4f5a-b70d-f558273101b5/ NewFileAgentInventory                 /CAPS/f608dd70-15f1-40a9-8780-8164c09627680002/ FetchInventory2                       /CAPS/176542be-6a06-4219-8647-cb57f8c9ec20 ...                               GetTexture                             http://192.168.1.2:8010/CAPS/GetTexture/
 * User f2f493c0-27d3-4cf2-be97-b44dfdad13b6:

This is because there is currently no mechanism for generating a random capability URL when a capability is being provided directly by a service. So in this case, for instance, anybody who knows the fixed GetTexture URL can request an asset if they know its ID. In the case of GetTexture, this is not considered a critical problem since there are many ways of fetching an arbitrary asset if the ID is known (though in cases of grids with restricted membership this might still be considered a problem). However, in other cases, such as the FetchInventory2 capability, this is a much more considerable problem. Ultimately, a mechanism for the simulator to register a random capability endpoint with the service hosting the capability will have to be implemented though this increases the complexity of the system.

Some connectors cannot handle Hypergrid
Currently, at least some capability connectors cannot operate in Hypergrid mode (though this isn't an issue with GetTexture). This situation will evolve in the future.