Wednesday, December 15, 2010

Forwarding XML-RPC

I've always struggled with GUIs for embedded systems.

Our robots generally run linux. Generally, the systems run w/out monitors or keyboards, so the best option is to ssh into a linux box, with X11 forwarding turned on, and pretend like I was at the terminal. This is great as long as you have a laptop. The question is how I could do this in a more platform agnostic way. It'd be great if I had one GUI for windows/linux/mac/ios/etc, and if that GUI required no software installation.

Since GUI programming isn't my forte, and my GUIs literally just call my API functions with a lot of extra code for layout, this seemed like a great opportunity to fuse web and embedded software. Since we had used xmlrpc before, it seems to work OK, and there were javascript libraries for it, I decided to try writing my gui in a webpage with javascript, and write a xmlrpc wrapper for my robot api.

The first issue I ran into was a security limitation on the XMLHTTPost function in javascript. You can only post to the server the script came from. That extends to the port on the server the script came from. Since xmlrpc runs over HTTP, it has to be a different port than my GUI webpage (served by apache).

This was a pain, but I got around it by writing what is effectively a xmlrpc forwarder.

I created a php file with the following content:

1:  // Make Sure that it's a POST request that we're forwarding
2: if ( $_SERVER['REQUEST_METHOD'] === 'POST' )
3: {
4: // Read the input from stdin
5: $data = trim(file_get_contents('php://input'));
6: }
7: // initialize curl
8: $ch=curl_init();
9: // The URL of our actual server
10: $url="http://localhost/RPC2";
11: // The XML payload is the data that was posted, with the XML tag
12: define('XML_PAYLOAD', '<?xml version="1.0"?>'."\n".$data);
13: // Set all the options for cURL
14: curl_setopt($ch,CURLOPT_URL,$url);
15: // Running on port 8080
16: curl_setopt($ch,CURLOPT_PORT,8080);
17: // Get request is default, make this a POST
18: curl_setopt($ch,CURLOPT_POST,1);
19: curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
20: curl_setopt($ch, CURLOPT_TIMEOUT, 4);
21: curl_setopt($ch, CURLOPT_POSTFIELDS, XML_PAYLOAD);
22: // This has to be set for it to be an XML post
23: curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/xml"));
24: $myFile = "/tmp/xml_forward_debug.txt";
25: $fh = fopen($myFile, 'w') or die("can't open file");
26: fwrite($fh, XML_PAYLOAD);
27: fwrite($fh, "\n\n*** Response\n\n");
28: $ret=curl_exec($ch);
29: fwrite($fh, $ret);
30: fclose($fh);
31: header('Content-Type: text/xml');
32: print $ret;

My javascript uses mimic.

My C++ server uses xmlrpc for c++

My test web post calls the classic "add" method



1:       var request = new XmlRpcRequest("index.php", "sample.add"); 
2: request.addParam(1);
3: request.addParam(3);
4: var response = request.send();
5: alert(response.parseXML());

This all seems to work so far! Very exciting. Still quite a ways to go as I work out messaging, etc., but I'm hoping this was the biggest step. Will post more as the project progresses.

No comments: