What is XML-RPC?
XML-RPC (remote
procedure calling) is a specification and set of implementations that allow software running on disparate operating systems running in different environments to make procedure calls over the Internet.
Its remote procedure calling uses
HTTP as the transport and XML as the encoding. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed, and returned.
The
URL for sending XML-RPCalls to a
script is:
http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi
The
name for a request is:
llRemoteData
Parameters must be a
struct(ure) consisting of :
string Channel, string StringValue, int Int[[value Value]] (see example requests below)
If "XML-RPC" is simply too long to type out and you feel you must abbreviate it, don't call it "XML", call it "RPC". Describe it by what it does, not by the data format it uses. Everything uses XML now anyway.
Event:
remote_data
Functions:
Constants:
REMOTE_DATA_CHANNEL | successful llOpenRemoteDataChannel |
REMOTE_DATA_REQUEST | request received |
REMOTE_DATA_REPLY | reply received |
Warning
The performance of XML RPC has been steadily degrading over the last year. If you need reliable communications that originate from outside of SL you're likely better off polling with HTTP requests. XML RPC requests are typically taking 60 seconds or more to complete these days, and not completing at all quite frequently. For more information, search for XMLRPC on the scripter forums.
IMPORTANT IMPLEMENTATION NOTES:
The current implementation of XML-RPC only allows ONE request to be queued on the front-end server (xmlrpc.secondlife.com) at a time. Any additional requests to the same data channel overwrite any pending one. This has serious ramifications for the design of XML-RPC communications where the in-world object could receive requests faster than it can respond to them. In addition, the 3-second delay in llRemoteDataReply exacerbates this problem even more.
The observed issue is this: if you send multiple quick requests to an in-world object via XML-RPC, one which is scripted to perform some processing and then return a response (via llRemoteDataReply), there is a potential for earlier requests to get lost on the front end server (they still should generate remote_data events, though), and have the response meant for an earlier request end up being passed back to a later one, while the earlier requests will time out back at your external application.
As a result, if you intend to do any serious work with XML-RPC, you will have to design your external client application to manually serialize all requests to each individual RPC channel. That means you have to wait for a response from the previous request before you attempt to send the next one. If you don't care about receiving responses, then this problem is not an issue, as all requests seem to get passed on to the script, regardless of the queueing issue.
Also note that there is NO way to get around the 3-second delay for llRemoteDataReply; you cannot use the multiple-slave-comm-script trick, because XML-RPC channels are *script-specific*, NOT *object-specific*.
For more information, see these forum threads here and here.
--
TalarusLuan
Like llRemoteDataReply, the length of the sdata field passed by the remote_data event is also limited to 254 bytes
The implementation is at the sim level. When moving across region borders the channel must be re-established in the new region. This can be done in a changed event. See the notes under llOpenRemotedataChannel for further details.
--
KeikoRau
Examples
LSL
Example Request
Example Response
LSL Example:
// XML-RPC example
key gChannel; // my llRemoteData channel
DEBUG(list out) { // output debug info
llSay(0, llList2CSV(out));
}
default { // initialize XML-RPC
state_entry() {
llOpenRemoteDataChannel(); // create an XML-RPC channel
// this will raise remote_data event REMOTE_DATA_CHANNEL when created
}
remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) {
if (type == REMOTE_DATA_CHANNEL) { // channel created
DEBUG(["Channel opened", "REMOTE_DATA_CHANNEL", channel, message_id, sender, ival, sval]);
gChannel = channel;
llSay(0, "Ready to receive requests on channel \"" + (string)channel +"\"");
state go; // start handling requests
} else DEBUG(["Unexpected event type", type, channel, message_id, sender, ival, sval]);
}
}
state go { // handle requests
remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) {
if (type == REMOTE_DATA_REQUEST) { // handle requests sent to us
DEBUG(["Request received", "REMOTE_DATA_REQUEST", channel, message_id, sender, ival, sval]);
// handle request
if (sval == "How are you?") { // we do something special on that string parameter
// send a reply to this request, referencing the senders message id
llRemoteDataReply(channel, message_id, "Fine, thanks!", 1);
} else { // IMPORTANT: a reply MUST always be sent
llRemoteDataReply(channel, message_id, "", 0);
}
} else DEBUG(["Unexpected event type:", type, channel, message_id, sender, ival, sval]);
}
state_exit() {
llCloseRemoteDataChannel(gChannel); // clean up when you no longer want to handle requests
}
}
Example request:
<?xml version="1.0"?>
<methodCall>
<methodName>llRemoteData</methodName>
<params>
<param>
<value>
<struct>
<member>
<name>Channel</name>
<value><string>4a250e12-c02e-94fb-6d2f-13529cbaad63</string></value>
</member>
<member>
<name>IntValue</name>
<value><int>0</int></value>
</member>
<member>
<name>StringValue</name>
<value><string>test</string></value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
Example response:
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>Channel</name>
<value><string>6df57cf4-68b7-b958-5b6c-10cb9f2fa391</string></value>
</member>
<member>
<name>StringValue</name>
<value><string>Monkey</string></value>
</member>
<member>
<name>IntValue</name>
<value><int>0</int></value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>
Want to complain about XML-RPC's implementation? Have you come up with an idea for a better solution? See
XML-RPC Discussion.
For XML-RPC implementations in a variety of languages, see
XMLRPCImplementations.
LuccaKitty: The above example requests and responses are fine if you already have a simple http post app, but that wasn't the case for me, i had to construct an entire http post packet from scratch. I'm posting the http post packet in it's entirety below. This will be useful if you intend on sending raw packets to make a quick and dirty client app. Maybe needs a refactoring. I apologise for the code scrolling off the example box. When generating said packet, I was attempting to keep the actual amount of data to a minimum to conserve bandwidth. I would format the packet, except that you'll notice Content-Length: 411. If I refactor it, the packet is no longer actually usable, as it changes the content length of the request. Hope this helps someone.
Example request entire raw packet:
POST /cgi-bin/xmlrpc.cgi HTTP/1.0
Host: xmlrpc.secondlife.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 411
<?xml version="1.0"?><methodCall><methodName>llRemoteData</methodName><params><param><value><struct><member><name>Channel</name><value><string>51ef73f1-14d6-a6c3-b6b6-dbacaa4127d5</string></value></member><member><name>IntValue</name><value><int>11261979</int></value></member><member><name>StringValue</name><value><string>happy birthday</string></value></member></struct></value></param></params></methodCall>
Example PHP script showing how to put together a http-post:
https://wiki.secondlife.com/wiki/Category:LSL_XML-RPC#php
Links
current XML-RPC specification
XML-RPC.com
Functions |
Communications |
XML-RPC Discussion |
XML-RPC Implementations Despammed