Difference between revisions of "OGP LLSD Draft 3"

From Second Life Wiki
Jump to navigation Jump to search
(New page: <span style="font-size: 200%;">Open Grid Protocol: Foundation</span> :<small>'''Draft 3'''</small> :<small>'''September 2008'''</small> ::''Notice: This draft is for public comment. '' ::...)
 
 
(2 intermediate revisions by one other user not shown)
Line 1: Line 1:
<span style="font-size: 200%;">Open Grid Protocol: Foundation</span>
<span style="font-size: 200%;">Open Grid Protocol: LLIDL, LLSD and Structured Data Serialization</span>
:<small>'''Draft 3'''</small>
:<small>'''Draft 3'''</small>
:<small>'''September 2008'''</small>
:<small>'''September 2008'''</small>
Line 5: Line 5:


::<small>Mark Lentczner (Zero Linden) Linden Lab zero.linden@secondlife.com</small>
::<small>Mark Lentczner (Zero Linden) Linden Lab zero.linden@secondlife.com</small>
::<small>Meadhbh Hamrick (Infinity Linden) Linden Lab infinity@lindenlab.com</small>
::<small>Copyright 2008, Linden Lab. All rights reserved. </small>
::<small>Copyright 2008, Linden Lab. All rights reserved. </small>


::<small>This work is licensed under the Creative Commons Attribution-Share Alike 3.0 license. See http://creativecommons.org/licenses/by-sa/3.0/for details. </small>
::<small>This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 license. See http://creativecommons.org/licenses/by-sa/3.0/for details. </small>


::<small>All contributions to this document must be contributed under the Second Life Project Contribution Agreement. See http://wiki.secondlife.com/wiki/Project:Contribution_Agreementfor details </small>
::<small>All contributions to this document must be contributed under the Second Life Project Contribution Agreement. See http://wiki.secondlife.com/wiki/Project:Contribution_Agreementfor details </small>


:<small>'''Abstract'''</small>
:<small>'''Abstract'''</small>
::<small>The Second Life Open Grid Protocol documents define the protocols by which a vast, Internet wide virtual world can operate. This protocol enables different regions of the virtual world to be operated independently, yet interoperate to form a cohesive experience. </small>
::<small>Services in the Open Grid Protcol are defined in terms of uniquely addressable stateful resources. These resources are used by client applications to query the state of distributed objects and to request state transitions in those objects. Interfaces to these resources are defined using the Linden Lab Interface Description Language (LLIDL). Resource requests and responses are defined in terms of abstract types. The Linden Lab Structured Data (LLSD) specification defines the type system and serialization methods to convert between abstract structured data and a sequence of octets suitable for transmission across a network. </small>
 
::<small>LLIDL and LLSD are designed to match the facilities available in many dynamic programming languages, so that data may be represented in native data structures and accessed using built-in methods. Implementations also exist for non-dynamic languages providing easy access to concrete data structures defined using LLSD's abstract type syntax. </small>


:<small>'''Status'''</small>
:<small>'''Status'''</small>
::<small>As of Summer 2008, this protocol is a work in progress. While the major structural elements have been designed, the specific elements for many needed resources have not. This work is being undertaken by Linden Lab and its community based Architecture Working Group. </small>
::<small>As of April 2008, LLSD has been defined and in use within Linden Lab for over three years. The version in use has been documented on Linden Lab's public wiki for over a year. This version differs only in recasting that wiki document into a standard format and formal specification of LLIDL. </small>
 
::<small>This protocol is being defined in light of feature set of Second Life. For now, where this document is currently lacking details, familiarity with Second Life will be assumed. It is an express aim of this work to enable the live, gradual migration of Second Life to using this new protocol as the development proceeds. </small>


{{RightToc}}
{{RightToc}}
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 1 Structure | discuss]]</span>
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 1 Abstract Interface Definition | discuss]]</span>
== Structure ==
== Abstract Interface Definition ==


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 1-1 Domains | discuss]]</span>
As described in a previous section, the Open Grid is a distributed application executing concurrently on a widely scattered collection of systems. There is no one system or server that "runs the grid" but a constellation of systems, each maintaining the state of a collection of virtual objects. These objects interconnect, defining an "object graph" that at any time defines the state of the virtual world through the state of each of the objects and the references they hold to each other.
=== Domains ===


This protocol is about a three way interaction between viewer, agent and region in order to facilitate a shared experience between people.  
To insure the harmonious inter-operation of each of the systems participating in the virtual world, well defined interactions describe unambiguously how changes in state are communicated between distributed objects.  


The viewer is the element that senses and acts on the state of the virtual world. The viewer does so from the vantage point of an agent. An agent is persistent identity and persona that interacts in a virtual world. The agent persists and can be interacted with even when the user controlling it (though a viewer) is off-line. Regions are persistent locations in the virtual world. Multiple agents may be present in a region at the same time, and when they are they have a shared experience.


Groups of regions and agents are managed by domains. A region domain is responsible for a collection of regions. An agent domain manages agent accounts.
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 2 Type System | discuss]]</span>


This protocol makes few assumptions about how a domain manages its collection of elements. In particular, it does not assume that a region will be entirely managed on a single host, nor that an agent will or won’t be managed by a single process.
== Type System ==


It is useful to think of the “stance” that each element takes in the three-way protocol:
An LLSD value is either a simple datum or a composite structure. A simple data value may be accessed as a particular type, which influences how the data is interpreted. In general, a value that is transmitted or stored as one type, can be accessed as another, in which case well defined conversions govern how the data is transformed. In particular, it is expected that LLSD data may be serialized in systems with fewer types (e.g. JSON), or stored in native programming language structures with less percise types, and yet still interoperate in a predictable, reliable manner. Similarly, the two available composite structures, arrays and maps, have a consistent semantics that can be achieved accross a wide variety of systems.


The viewer is the direct proxy for a human that wants to control an agent. This control can be direct as in the case of an interactive 3D viewer, or indirect as in the case of a web site that the user directs to display their agent’s status.
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 2-1 Simple Types | discuss]]</span>
=== Simple Types ===


The agent domain is responsible for the agent itself. The persistent state of the agent is held within the agent domain, and requests to interact with the agent, even by the viewer, are mediated by the agent domain.  
For each type, conversions are defined to that type. That is, if a process is accessing a particular LLSD value, and treating it as a particular type, but the underlying type (as transmitted, or stored in memory) is different, then the indicated conversion, if available, is applied. If a conversion is not specified from a particular type, then if a value of that type is accessed, the result is the default value for the expected type. For example: When reading a value as an integer, if the underlying value is binary, then 0 is the value read.  


The region domain runs the live simulations of regions in the virtual world. The region domain manages the persistent state of these regions.  
::''Note: A number of normative references need to be looked up, and properly referenced: UUID formats, Date formats, URI formats. ''


::''Note: A number of conversions need better defintions: to/from numeric values and strings, handling NaNs and Infs when converting from (to?) Real, ''


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 1-2 Basic Flow | discuss]]</span>
::''Note: Some currently implemented conversions were ommitted as they hadn't be concieved as part of the standard. These are Map and Array to Boolean, and Date to/from Integer and Real. ''
=== Basic Flow ===


The basic flow of the protocol is:
::''Note: There are conversions listed in the public wiki LLSD page to and from Binary that are not implemented and have never been relied on. They have also been omitted. ''


# The viewer authenticates to an agent domain for the authorized control of a particular agent.
==== Type: Undefined ====
# The viewer directs the agent domain to to place the agent in a region.
# The agent domain contacts the region domain for the region, and negotiates placement of the agent.
# The region grants access to the agent domain, which in turn passes some of that granted access on to the viewer.


At this stage, each entity will have access to many resources in the other entities. For example:
Data of type undefined has only one value, called undef. The default value is undef. There are no defined conversions to undefined.  


* The viewer has access to region resources that let it move the avatar.
* The region has access to viewer resources that update the state of objects in the region.
* The viewer and agent have access to resources in each other to facilitate text messaging.


==== Type: Booolean ====


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 1-3 Structure of the Protocol | discuss]]</span>
Data of type boolean has only two values, true and false. The default value is false.
=== Structure of the Protocol ===


The protocol is fundamentally composed of individual resources that can be invoked by one entity in the system upon another. Each resource is a member of a resource class that describes the syntax and semantics of invoking the resource. The bulk of this document, when complete, will describe the several hundred resource classes that make up the virtual world.
Conversions:


The resource classes are composed into suites that form logical groupings, though suites do not otherwise play a part in the protocol.
{| border="1"
|-
|
Integer
|
0 -> false, all other values -> true
|-
|
Real
|
all NaNs, and exactly 0 -> false, all other values -> true
|-
|
String
|
the empty string -> false, all others are true
|}


In order to facilitate migration from the currently running version of Second Life, legacy resources return information that allow entities to continue to communicate using the existing protocols and structures. These protocols and structures are not described by this document. It is the intention that when this work is complete, none of these legacy resources will be in use.


Agent and region domains have a few resources that are available at well known URLs. All other resources in the agent and region domains are accessed via capabilities obtained from the those few initial resources.
==== Type: Integer ====


Since viewers are typically behind firewalls that do not allow connection, resources in the viewer are accessed by event queues held in the agent and region for the viewer. The viewer uses the ‚Äúlong poll‚Äù technique to efficiently proxy these inward resource invocations.  
Data of type integer contains signed integral values from the range available with a 2s complement 32-bit binary representation. Integer values outside this range may not be representable. The default value is zero (0).  


Conversions:


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 1-4 Document Structure | discuss]]</span>
{| border="1"
=== Document Structure ===
|-
|
Boolean
|
true becomes 1, false becomes 0
|-
|
Real
|
rounded to closest representable number, all NaNs -> 0
|-
|
String
|
the string is converted first to a Real, then converted as a Real
|}


OGP is a large suite of interrelated protocols. Each major protocol set is described in its own document. For examples, see the OGP Authentication and OGP Teleport documents. This document describes the base facilities and concepts upon which the other protocols are based. To be compliant with OGP, an implementation must conform to this document, and may implement any of the other protocol sets that are deemed relevant.


==== Type: Real ====


Data of type integer contains signed floating percesion numeric values from the range available with IEEE 754 64-bit double percsion values. Integer values outside this range may not be representable. The default value is zero (0).


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 2 Base Protocols | discuss]]</span>
Conversions:  
== Base Protocols ==


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 2-1 Resources, HTTP & REST | discuss]]</span>
{| border="1"
=== Resources, HTTP & REST ===
|-
|
Boolean
|
true becomes 1, false becomes 0
|-
|
Integer
|
integral value as a real
|-
|
String
|
if the entire string is the decimal representation of a value, then that value, othewise 0
|}
 
 
==== Type: String ====
 
Data of type string contains a sequence of zero or more Unicode characters. The default value is the empty string.


All interaction between entities is through a client invoking a resource. Resources are invoked either directly via HTTP, or through an event queue.
The characters are restricted to the following code points:


For each resource class, this protocol defines how the client obtains the URL, the HTTP verb (or verbs) to be used, the request and response bodies (if any), and significant status codes. Resource classes are designed with REST style semantics.
* U+0009, U+000A, U+000D
* U+0020 through U+D7FF
* U+E000 through U+FFFD
* U+10000 through U+10FFFF


In general, HTTP & REST are used as follows: The URL will be either well-known in advance or returned in a response from another resource. The latter is called a capability. Except for security reasons, URLs are always treated as opaque. Clients should not modify them. Parameters are never added to them via the query section. Resource handlers must be prepared to ignore query sections.  
Strings may be normalized during transport. When an implementation does normalize, it  >>> rfc2119
should use Normalization Form C (NFC). Line endings may be normalizaed during transport to U+000A.  


Resources follow general REST semantics and so respond to one of these verb sets:  
Conversions:  


{| border="1"
{| border="1"
|-
|-
|
|
GET
Boolean
|
true becomes "true", false becomes the empty string ""
|-
|
Integer
|
decimal representation of value, with leading hypen for negative values
|-
|
Real
|
|
for cacheable resources
decimal representation of vlaue, using common signed exponent notation, with enough digits to represent full percision
|-
|-
|
|
GET, PUT
UUID
|
|
for cacheable resources that can be modified
36 character hexadecimal representation with hyphens, as per RFC xxx
|-
|-
|
|
GET, PUT, DELETE
Date
|
|
for cacheable resources that can be modified and deleted
the ISO-8601 numeric representation of the date
|-
|-
|
|
POST
URI
|
|
for non-cacheable resources
the URI value as a string
|}
|}


Unless otherwise stated, if a resource accepts PUT, it accepts multiple PUT invocations.
::''Note: We are considering having all resources support OPTIONS ''
The request and response bodies are transmitted as serialized LLSD data. If a resource has no response defined, then it can return either an undefined value, an empty map, or have a zero length response body.
HTTP status codes should only be used to indicate the status of the HTTP interaction itself. In general, if the resource is reachable, and the request understood, a 2xx code should be returned.


::''Note: Something about redirection - is it supported? Probably not… ''
==== Type: UUID ====


HTTP headers, both for the request and the response are never part of a resource class definition. Headers are handled as per the HTTP standard.  
Data of type integer contains an unsigned 128 bit number. The default value is the null UUID, consisting of 128 zero bits.  


Only conversion from String is defined: strings in the RFC xxx 36 character format are intepreted as per that specification, all others are null UUID.


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 2-2 LLSD | discuss]]</span>
=== LLSD ===


All data in this system is defined by LLSD. LLSD is an abstract way of talking about structured data. It is defined in the document "LLSD".
==== Type: Date ====


::''Note: This needs to be a normative reference. ''
A specific point in UTC time. Intervals or relative dates are not supported. The default date is the common "epoch": January 1st, 1970, Midnight UTC.  


==== Serialization ====
Only conversion from String is defined: strings are interpreted as per ISO-8601 if the whole string can, otherise the default date.


When used as part of OGP, the XML and JSON serializations of LLSD  >>> rfc2119
must be supported.


::''Note: As deployed, only XML serialization is implemented. ''
==== Type: URI ====


A string of characters representing a URI, as per RFC xxxx. The default value is an empty URI.


Only conversion from String is defined: strings that can be interpreted as a valid URI are treated as a URI, otherwise the default URI.


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 2-3 Capabilities | discuss]]</span>
=== Capabilities ===


This protocol makes extensive use of capabilities. A capability is an opaque HTTP (or HTTPS) URL used for accessing a particular resource. The provider of the resource has three logical parts: the ''grantor '', the ''capability host '', and the ''service ''.
==== Type: Binary ====


The grantor uses the capability host to construct a capability that maps to the service that provides the resource, then returns that capability to the client. At some point in the future, the client invokes the capability which makes a connection to the capability host. The capability host then proxies to the service to provide the resource.  
An ordered sequence of zero or more octets. The defalut value is the empty sequence. There are not defined conversios to Binary.  


The parts that make up the provider may be separate entities or may be the same.


The client can’t invoke the resource without the capability. Typically the capability is a URL with a cryptographically secure path component. Within the capability host, this URL is mapped to the actual internal resource URL.


The client is free to hand the capability to other entities who become clients of the capability as well. Other than for the security considerations below, the client must not rely on any assumed structure of the capability URL.


==== Obtaining ====
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 3 Serialization | discuss]]</span>
== Serialization ==


For each resource a client wants to invoke, the capability must be obtained. In a few cases, the capability will have been expressly returned in the result of some other resource. Usually, the system uses a seed capability (see below) to request the capability for a given resource by name.  
When used as part of a protocol, LLSD is serialized into a common form. At present, the only serialization is the XML LLSD serialization. In the future, other serializations may be supported, in particular binary LLSD and JSON. The serialization format is negotiated and indicated using the normal facilities of HTTP.  


The MIME type for the XML serialization of LLSD is:


==== Invocation ====
application/llsd+xml


To invoke a capability, the holder performs an HTTP transaction with the capability as the URL. The resource class the capability represents will dictate which verb (or verbs) can be used, and what the request and response bodies (if any) should be.
::''Note: JSON only allows maps and arrays as top level elements. Do we need to impose the same restriction on LLSD as used in resource requests and responses? ''




==== Lifetime & Revocation ====
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 4 Linden Lab Interface Description Language (LLIDL) | discuss]]</span>
== Linden Lab Interface Description Language (LLIDL) ==


Capabilities can be either unlimited or one-shot. Unlimited capabilities can be used multiple times, whereas one-shot can be used only once and are automatically revoked on invocation.  
LLIDL (pronounced "little") is the language used to describe the interface to resources in the Open Grid Protocol. LLIDL is born of the need to unambiguously define interfaces independent of serialization schemes. Rather than defining BOTH JSON and XML interfaces, the OGP specification defines interfaces in terms of LLIDL which may then be mechanically converted into message parsers and generators for supported serialization schemes. The objective of LLIDL is therefore to provide a language for describing OGP messages that is human-readable but easily parsed by automated tools.  


::''Note: If we support the OPTIONS method, then invoking a one-shot with OPTIONS does not revoke it. ''
OGP compliant systems expose "interfaces" to "resources." Each resource is an instance of a "resource class" which defines it's interface in a manner analogous to the way a "class" defines methods exposed by an object in an object-oriented programming environment. Interaction with an OGP compliant system is through messages which conform to a resource's interface. In the same way that LLSD defines the formatting rules for a valid message, LLIDL defines which LLSD messages are valid for a particular interface.  


::''Note: What about using HEAD on a one-shot? ''
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 4-1 Abstract Data Types and Name | discuss]]</span>
=== Abstract Data Types and Name ===


Any capability can be revoked at will by the provider of the resource. Clients must be prepared to handle revoked capabilities. A revoked capability, when invoked must return a 4xx HTTP status code. The capability host may return a 404, even if the capability had been previously active.  
The core objective of LLIDL is to define abstract data structures for OGP resorces. To achieve this objective, LLIDL defines interfaces in terms of parameter names and parameter types. The association of a parameter name with a type is created by listing the parameter name, a colon and a parameter type.  


parameter name : parameter type


==== Names ====


The resource a capability performs is identified by name. When requesting a capability, or when returning a capability, the opaque URL is identified with this name. The names of such resources are intended to be globally unique.
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 4-2 Abstract Data Structures | discuss]]</span>
=== Abstract Data Structures ===


Names are URIs. When a name appears without a scheme component, then it is a relative URL, considered relative to the base:
Collections of abstract type and name associations are defined as either lists or maps. Arrays represent a collection of items accessed by a numeric index while maps represent a collection accessed by a string key. The first example below defines an array with three real numbers, while the second defines a map with two strings.


  http://xmlns.secondlife.com/capability/name/
  [ real real real ]
                   
{ first_name: string, last_name: string }


While names do exhibit path-link structure, they are to be considered opaque identifiers. For example, while the following three capability names are indeed from the same sub-system, nothing should be inferred about a capability that starts with their common prefix:
Arrays are delimited with the  >>> emph
[ and  >>> emph
] (open and close square brackets) characters while maps are delimited with the >>> emph
{ and  >>> emph
} (open and close brace) characters.


<blockquote>
It is important to note that LLIDL defines an  >>> emph
* inventory/root
abstract language. It is used to specify the "shape" and contents of valid messages; it is not used as a serialization format. LLIDL is used to define
* inventory/folder_contents
* inventory/move_folder


</blockquote>
While not required, this protocol prefers names that are all lower case roman letters, separated by underscores.


<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 4-3 Variant Structures | discuss]]</span>
=== Variant Structures ===


==== Seed Capability (Resource Class) ====
Often times it is advantageous to represent several different variants of a message. LLIDL defines variants with repeated assignments to the same variant name. In the example below, two "exception" variants are defined, the first with two strings, and the second with a number and a string.


In many cases, a sub-system will return a ''seed capability ''from which other capabilities can be requested.  
Note there is no special meaning to the name "exception" save that afforded it by the protocol that uses it. In short, the term "result" or "condition" or even "oak_tree" could have been used and there would be no difference in the result (save potential confusion by users.)


{| border="1"
&exception = {
|-
  class      : string ,
| colspan="2" |
  description : string
Seed Cabability
  }
|-
|
Name
|
various, this is a generic resource and used in a variety of places
|-
|
URL
|
various
|-
|
Verb
|
POST
|-
|
Request
|
{ capabilities: [ ''name1, name2, … ''] }
|-
|
   
|
an array of the names of the capabilities being requested
|-
|
Response
|
{ capabilities: { ''name1: url1, name2: url2, ‚Ķ ''} }  
|-
|
   
   
|
&exception = {
a map from the names requested to granted capabilities.
  class      : int ,
|}
  description : string
}


The request contains an array of all resource names for which capabilities are desired. The response contains a map with an entry for each capability granted. Note: a grantor may grant all, some or none of the requested capabilities. The grantor may also grant additional capabilities that were requested, or none at all. If the grantor grants none, the response array must be empty and the HTTP status code should still be 200.
==== Optional Parameters and Defaults ====


::''Note: The seed capability protocol deployed today uses the 'caps' key instead of 'capabilities' ''
One interesting aspect to LLIDL and LLSD is that when a structure is serialized, there is no semantic difference between an item being present with its default value and the item being completely absent. For instance, given the following structure:  


&condition = {
  error      : boolean,
  description : string
}


==== Security ====
Each of the following XML LLSD serializations are valid:


If an end-point receives a capability from an untrusted source, it is permissible for security reasons to check the following aspects of the URL before use:
<?xml version="1.0"?>                                                           
<llsd>                                                                                                                             
  <map>                                                                         
    <key>error</key>                                                     
    <boolean>true</boolean>                                               
    <key>description</key>                                               
    <string>loose nut behind keyboard</string>                           
  </map>                                                                       
</llsd>                                                                         
<?xml version="1.0"?>                                                           
<llsd>                                                                                                                           
  <map>                                                                         
    <key>error</key>                                                     
    <boolean>false</boolean>                                             
  </map>                                                                       
</llsd>                                                                         
                       
<?xml version="1.0"?>                                                           
<llsd>                                                                                                                             
  <map>                                                                         
  </map>                                                                       
</llsd>             
                   


* The scheme should be http: or https:.
To recap, from a semantic perspective, deserializing a LLSD XML object in which an item is missing is identical to that item being present with the default value for it's type.  
* The authority (in particular, the resolved host name) should not resolve to ports on the local machine that aren‚Äôt publicly accessible.  






<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 2-4 Event Queues | discuss]]</span>
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 4-4 Literal Discriminators | discuss]]</span>
=== Event Queues ===
=== Literal Discriminators ===


An event queue enables an entity to invoke resources in the viewer, which cannot be directly contact via HTTP. This is usually the case because the viewer is behind a firewall that doesn‚Äôt allow incoming TCP (and hence HTTP) connections from the region or agent domains.  
In the "exception" example above, two variants of a structure differ by the type defined for the "class" structure element. We also know that assertions may be missing from the serialization of an LLIDL object. It is often useful in these situtations to use boolean or string literals to distinguish variants of an object.  


In such a situation, the client establishes a queue of invocation requests for resources in the viewer. At the same time, the viewer uses an '''event_queue/get '''capability to effectively tunnel the requests from the client to itself.  
In this example we see a boolean used to differentiate the two variants.  


::''Note: The event queue protocol described here matches what is deployed today, but is limited in functionality. It is expected to be superseded by a more general facility soon. ''
&response = {
  success    : false ,
  description : string ,
  err_num    : integer
}
&response = {
  success    : true,
  description : string
}


::''Note: The deployed event queue on the agent domain ''
In the following example, we use a string to differentiate the classes of exception.


==== Restrictions ====
&exception = {
  class      : 'encoding' ,
  description : string
}
&exception = {
  class      : 'method' ,
  description : string ,
  result      : int
}
 
&exception = {
  class      : 'parsing' ,
  description : string ,
  line_num    : int ,
  column_num  : int 
}


Resources accessed this way have the following restrictions:


* Resources are identified by their resource class name. With capabilities, there can be several resources in an entity that all conform to the same resource class. With event queues only one resource can exist for each resource class within the viewer. This is not usually a severe restriction.
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 4-5 Defining a Resource Interface | discuss]]</span>
::''Note: The next three are temporary limitations in the current protocol and are expected to be removed. Resource classes that conform to these restrictions are equivalent to messages in the current Second Life protocol. ''
=== Defining a Resource Interface ===


* The only verb allowed is POST.  
Defining interfaces is the underlying purpose of LLIDL. Each interface has a name, an input definition and an output definition. They are specified using the following format:
* No response body is allowed.  
* The only status codes are 200, or 500 if the queue shuts down before all events are ack’d.


%% resource name -> request <- response


==== Requests ====
As an example, a resource that takes no inputs and returns a string value could be declared as:


The event queue is an unordered list of requests. Each request is formatted as follows:
%% version -> undef <- string


<blockquote>
{ message: ''name '', body: ''arbitrary-data ''}


</blockquote>
<span style="float:right; font-size:80%; color:red;">[[SLGOGP_Draft_1/Discuss 4-6 Full ABNF of LLIDL | discuss]]</span>
=== Full ABNF of LLIDL ===


==== Basic Flow ====
value          = type / array / map / selector / variant
 
When the viewer invokes '''event_queue/get ''', the entity replies with the list of messages that have been queued up. The viewer takes the response, breaks it apart into a series of requests that it processes on itself, as resource invocations that the entity wanted to perform. When those invocations are processed, the viewer indicates in its next invocation of '''event_queue/get '''that the previous set was completed. While it takes two resource invocations of '''event_queue/get '''to tunnel a set of invocations in the other directions, subsequent transactions are chained, since the acknowledgement of a previous set of requests is performed in the same invocation that gets the next set.
type            =  "undef"
 
type            =/ "string"
 
type            =/ "bool"
==== Acknowledgement ====
type            =/ "int"
 
type            =/ "real"
The response to '''event_queue/get '''includes a sequence number for the batch of requests. When the viewer has processed a batch of requests, acknowledges them in the next invocation of '''event_queue/get '''. If unacknowledged, the event queue in the entity may either resend the same requests batched with any new requests, or may treat them as lost.
type            =/ "date"
 
type            =/ "uri"
 
type            =/ "uuid"
==== Long Poll ====
type            =/ "binary"
 
Both viewers and entities must be prepared to handle use the ‚Äúlong poll‚Äù technique to keep the flow of requests timely. Viewers must be prepared to handle that invoking '''event_queue/get '''may take a relatively long time to return, as the entity may choose to delay responding if there are no requests pending, or if it believes it would be better to wait for more requests to queue. Entities must be prepared to handle viewers that request as soon as they are ready for events with no delay. Both sides must be prepared to handle time outs and retries.  
array          =  "[" s value-list s "]"
 
array          =/ "[" s value-list s "..." s "]"
 
==== Closing the Queue ====
map            =  "{" s member-list s "}"
 
map            =/ "{" s "$" s ":" s value s "}"
When the viewer is ready to terminate the queue, meaning that it wishes to be done accepting requests, it may signal such by including the done flag in the next invocation of '''event_queue/get '''. This value is purely advisory, but enables entities to cleanly flush remaining events, and release resources.
 
value-list      = value [ s "," [ s value-list ] ]
 
==== Event Queue Get (Resource Class) ====
member-list    = member [ s "," [ s member-list ] ]
 
member          = name s ":" s value
This resource is a capability both in the agent and in the region, for implementing a tunneled series of resource invocations from the entity back to the client:
 
selector        =  quote name quote
{| border="1"
selector        =/ "true" / "false"
|-
selector        =/ 1*digit
| colspan="2" |
Event Queue Get
variant        = "&" name
|-
|
Name
definitions    = *( s / variant-def / resource-def )
|
event_queue/get
variant-def    = "&" name s "=" s value
|-
|
resource-def    = res-name s res-request s res-response
URL
res-name        = "%%" s name
|
res-request    = "->" s value
capability
res-response    = "<-" s value
|-
|
Verb
s              = *( tab / newline / sp / comment )
|
comment        = ";" *char newline
POST
newline        = lf / cr / (cr lf)
|-
|
Request
|
{ ack: ''sequence-number '', done: ''done-flag ''}
|-
|
   
   
|
tab            = %x0009
On the first invocation for a given resource, sequence-number must be undef. If done-flag is true, then the client is signaling its intention to stop polling if there are no more events.
lf              = %x000A
|-
cr              = %x000D
|
sp              = %x0020
Response
quote          = %x0022
|
digit          = %x0030-0039
{ id: ''sequence-number '', events: [ ''requests '', … ] }
char            = %x09 / %x20-D7FF / %xE000-FFFD / %x10000-10FFFF
|-
|
   
   
|
name            = name_start *name_continue
See above for format of requests. Events may be empty.See above for format of requests. Events may be empty.
name_start      = id_start    / "_"
|}
name_continue  = id_continue / "_" / "/"
id_start        = %x0041-005A / %x0061-007A ; ALPHA
id_continue    = id_start / %x0030-0039    ; DIGIT

Latest revision as of 12:35, 7 July 2009

Open Grid Protocol: LLIDL, LLSD and Structured Data Serialization

Draft 3
September 2008
Notice: This draft is for public comment.
Mark Lentczner (Zero Linden) Linden Lab zero.linden@secondlife.com
Meadhbh Hamrick (Infinity Linden) Linden Lab infinity@lindenlab.com
Copyright 2008, Linden Lab. All rights reserved.
This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 license. See http://creativecommons.org/licenses/by-sa/3.0/for details.
All contributions to this document must be contributed under the Second Life Project Contribution Agreement. See http://wiki.secondlife.com/wiki/Project:Contribution_Agreementfor details
Abstract
Services in the Open Grid Protcol are defined in terms of uniquely addressable stateful resources. These resources are used by client applications to query the state of distributed objects and to request state transitions in those objects. Interfaces to these resources are defined using the Linden Lab Interface Description Language (LLIDL). Resource requests and responses are defined in terms of abstract types. The Linden Lab Structured Data (LLSD) specification defines the type system and serialization methods to convert between abstract structured data and a sequence of octets suitable for transmission across a network.
LLIDL and LLSD are designed to match the facilities available in many dynamic programming languages, so that data may be represented in native data structures and accessed using built-in methods. Implementations also exist for non-dynamic languages providing easy access to concrete data structures defined using LLSD's abstract type syntax.
Status
As of April 2008, LLSD has been defined and in use within Linden Lab for over three years. The version in use has been documented on Linden Lab's public wiki for over a year. This version differs only in recasting that wiki document into a standard format and formal specification of LLIDL.

discuss

Abstract Interface Definition

As described in a previous section, the Open Grid is a distributed application executing concurrently on a widely scattered collection of systems. There is no one system or server that "runs the grid" but a constellation of systems, each maintaining the state of a collection of virtual objects. These objects interconnect, defining an "object graph" that at any time defines the state of the virtual world through the state of each of the objects and the references they hold to each other.

To insure the harmonious inter-operation of each of the systems participating in the virtual world, well defined interactions describe unambiguously how changes in state are communicated between distributed objects.


discuss

Type System

An LLSD value is either a simple datum or a composite structure. A simple data value may be accessed as a particular type, which influences how the data is interpreted. In general, a value that is transmitted or stored as one type, can be accessed as another, in which case well defined conversions govern how the data is transformed. In particular, it is expected that LLSD data may be serialized in systems with fewer types (e.g. JSON), or stored in native programming language structures with less percise types, and yet still interoperate in a predictable, reliable manner. Similarly, the two available composite structures, arrays and maps, have a consistent semantics that can be achieved accross a wide variety of systems.

discuss

Simple Types

For each type, conversions are defined to that type. That is, if a process is accessing a particular LLSD value, and treating it as a particular type, but the underlying type (as transmitted, or stored in memory) is different, then the indicated conversion, if available, is applied. If a conversion is not specified from a particular type, then if a value of that type is accessed, the result is the default value for the expected type. For example: When reading a value as an integer, if the underlying value is binary, then 0 is the value read.

Note: A number of normative references need to be looked up, and properly referenced: UUID formats, Date formats, URI formats.
Note: A number of conversions need better defintions: to/from numeric values and strings, handling NaNs and Infs when converting from (to?) Real,
Note: Some currently implemented conversions were ommitted as they hadn't be concieved as part of the standard. These are Map and Array to Boolean, and Date to/from Integer and Real.
Note: There are conversions listed in the public wiki LLSD page to and from Binary that are not implemented and have never been relied on. They have also been omitted.

Type: Undefined

Data of type undefined has only one value, called undef. The default value is undef. There are no defined conversions to undefined.


Type: Booolean

Data of type boolean has only two values, true and false. The default value is false.

Conversions:

Integer

0 -> false, all other values -> true

Real

all NaNs, and exactly 0 -> false, all other values -> true

String

the empty string -> false, all others are true


Type: Integer

Data of type integer contains signed integral values from the range available with a 2s complement 32-bit binary representation. Integer values outside this range may not be representable. The default value is zero (0).

Conversions:

Boolean

true becomes 1, false becomes 0

Real

rounded to closest representable number, all NaNs -> 0

String

the string is converted first to a Real, then converted as a Real


Type: Real

Data of type integer contains signed floating percesion numeric values from the range available with IEEE 754 64-bit double percsion values. Integer values outside this range may not be representable. The default value is zero (0).

Conversions:

Boolean

true becomes 1, false becomes 0

Integer

integral value as a real

String

if the entire string is the decimal representation of a value, then that value, othewise 0


Type: String

Data of type string contains a sequence of zero or more Unicode characters. The default value is the empty string.

The characters are restricted to the following code points:

  • U+0009, U+000A, U+000D
  • U+0020 through U+D7FF
  • U+E000 through U+FFFD
  • U+10000 through U+10FFFF

Strings may be normalized during transport. When an implementation does normalize, it >>> rfc2119 should use Normalization Form C (NFC). Line endings may be normalizaed during transport to U+000A.

Conversions:

Boolean

true becomes "true", false becomes the empty string ""

Integer

decimal representation of value, with leading hypen for negative values

Real

decimal representation of vlaue, using common signed exponent notation, with enough digits to represent full percision

UUID

36 character hexadecimal representation with hyphens, as per RFC xxx

Date

the ISO-8601 numeric representation of the date

URI

the URI value as a string


Type: UUID

Data of type integer contains an unsigned 128 bit number. The default value is the null UUID, consisting of 128 zero bits.

Only conversion from String is defined: strings in the RFC xxx 36 character format are intepreted as per that specification, all others are null UUID.


Type: Date

A specific point in UTC time. Intervals or relative dates are not supported. The default date is the common "epoch": January 1st, 1970, Midnight UTC.

Only conversion from String is defined: strings are interpreted as per ISO-8601 if the whole string can, otherise the default date.


Type: URI

A string of characters representing a URI, as per RFC xxxx. The default value is an empty URI.

Only conversion from String is defined: strings that can be interpreted as a valid URI are treated as a URI, otherwise the default URI.


Type: Binary

An ordered sequence of zero or more octets. The defalut value is the empty sequence. There are not defined conversios to Binary.



discuss

Serialization

When used as part of a protocol, LLSD is serialized into a common form. At present, the only serialization is the XML LLSD serialization. In the future, other serializations may be supported, in particular binary LLSD and JSON. The serialization format is negotiated and indicated using the normal facilities of HTTP.

The MIME type for the XML serialization of LLSD is:

application/llsd+xml
Note: JSON only allows maps and arrays as top level elements. Do we need to impose the same restriction on LLSD as used in resource requests and responses?


discuss

Linden Lab Interface Description Language (LLIDL)

LLIDL (pronounced "little") is the language used to describe the interface to resources in the Open Grid Protocol. LLIDL is born of the need to unambiguously define interfaces independent of serialization schemes. Rather than defining BOTH JSON and XML interfaces, the OGP specification defines interfaces in terms of LLIDL which may then be mechanically converted into message parsers and generators for supported serialization schemes. The objective of LLIDL is therefore to provide a language for describing OGP messages that is human-readable but easily parsed by automated tools.

OGP compliant systems expose "interfaces" to "resources." Each resource is an instance of a "resource class" which defines it's interface in a manner analogous to the way a "class" defines methods exposed by an object in an object-oriented programming environment. Interaction with an OGP compliant system is through messages which conform to a resource's interface. In the same way that LLSD defines the formatting rules for a valid message, LLIDL defines which LLSD messages are valid for a particular interface.

discuss

Abstract Data Types and Name

The core objective of LLIDL is to define abstract data structures for OGP resorces. To achieve this objective, LLIDL defines interfaces in terms of parameter names and parameter types. The association of a parameter name with a type is created by listing the parameter name, a colon and a parameter type.

parameter name : parameter type


discuss

Abstract Data Structures

Collections of abstract type and name associations are defined as either lists or maps. Arrays represent a collection of items accessed by a numeric index while maps represent a collection accessed by a string key. The first example below defines an array with three real numbers, while the second defines a map with two strings.

[ real real real ]
                    
{ first_name: string, last_name: string }

Arrays are delimited with the >>> emph [ and >>> emph ] (open and close square brackets) characters while maps are delimited with the >>> emph { and >>> emph } (open and close brace) characters.

It is important to note that LLIDL defines an >>> emph abstract language. It is used to specify the "shape" and contents of valid messages; it is not used as a serialization format. LLIDL is used to define


discuss

Variant Structures

Often times it is advantageous to represent several different variants of a message. LLIDL defines variants with repeated assignments to the same variant name. In the example below, two "exception" variants are defined, the first with two strings, and the second with a number and a string.

Note there is no special meaning to the name "exception" save that afforded it by the protocol that uses it. In short, the term "result" or "condition" or even "oak_tree" could have been used and there would be no difference in the result (save potential confusion by users.)

&exception = {
  class       : string ,
  description : string
}

&exception = {
  class       : int ,
  description : string
}

Optional Parameters and Defaults

One interesting aspect to LLIDL and LLSD is that when a structure is serialized, there is no semantic difference between an item being present with its default value and the item being completely absent. For instance, given the following structure:

&condition = {
  error       : boolean,
  description : string
}

Each of the following XML LLSD serializations are valid:

<?xml version="1.0"?>                                                            
<llsd>                                                                                                                               
  <map>                                                                          
    <key>error</key>                                                       
    <boolean>true</boolean>                                                
    <key>description</key>                                                 
    <string>loose nut behind keyboard</string>                             
  </map>                                                                         
</llsd>                                                                          

<?xml version="1.0"?>                                                            
<llsd>                                                                                                                             
  <map>                                                                          
    <key>error</key>                                                       
    <boolean>false</boolean>                                               
  </map>                                                                         
</llsd>                                                                          
                        
<?xml version="1.0"?>                                                            
<llsd>                                                                                                                              
  <map>                                                                          
  </map>                                                                         
</llsd>               
                    

To recap, from a semantic perspective, deserializing a LLSD XML object in which an item is missing is identical to that item being present with the default value for it's type.


discuss

Literal Discriminators

In the "exception" example above, two variants of a structure differ by the type defined for the "class" structure element. We also know that assertions may be missing from the serialization of an LLIDL object. It is often useful in these situtations to use boolean or string literals to distinguish variants of an object.

In this example we see a boolean used to differentiate the two variants.

&response = {
  success     : false ,
  description : string ,
  err_num     : integer
}

&response = {
  success     : true,
  description : string
}

In the following example, we use a string to differentiate the classes of exception.

&exception = {
  class       : 'encoding' , 
  description : string
}

&exception = {
  class       : 'method' ,
  description : string ,
  result      : int
}
 
&exception = {
  class       : 'parsing' ,
  description : string ,
  line_num    : int ,
  column_num  : int   
}


discuss

Defining a Resource Interface

Defining interfaces is the underlying purpose of LLIDL. Each interface has a name, an input definition and an output definition. They are specified using the following format:

%% resource name -> request <- response

As an example, a resource that takes no inputs and returns a string value could be declared as:

%% version -> undef <- string


discuss

Full ABNF of LLIDL

value           =  type / array / map / selector / variant

type            =  "undef"
type            =/ "string"
type            =/ "bool"
type            =/ "int"
type            =/ "real"
type            =/ "date"
type            =/ "uri"
type            =/ "uuid" 
type            =/ "binary"

array           =  "[" s value-list s "]"
array           =/ "[" s value-list s "..." s "]"

map             =  "{" s member-list s "}"
map             =/ "{" s "$" s ":" s value s "}"

value-list      = value [ s "," [ s value-list ] ]

member-list     = member [ s "," [ s member-list ] ]
member          = name s ":" s value

selector        =  quote name quote
selector        =/ "true" / "false"
selector        =/ 1*digit

variant         = "&" name


definitions     = *( s / variant-def / resource-def )

variant-def     = "&" name s "=" s value

resource-def    = res-name s res-request s res-response
res-name        = "%%" s name
res-request     = "->" s value
res-response    = "<-" s value


s               = *( tab / newline / sp / comment )
comment         = ";" *char newline
newline         = lf / cr / (cr lf)

tab             = %x0009
lf              = %x000A
cr              = %x000D
sp              = %x0020
quote           = %x0022
digit           = %x0030-0039
char            = %x09 / %x20-D7FF / %xE000-FFFD / %x10000-10FFFF

name            = name_start *name_continue
name_start      = id_start    / "_"
name_continue   = id_continue / "_" / "/"
id_start        = %x0041-005A / %x0061-007A ; ALPHA
id_continue     = id_start / %x0030-0039    ; DIGIT