samadhiweb

smalltalk programming for the web



RFB on Pharo 3

1 May 2014

Getting RFB to work is always an adventure. On the newly released Pharo 3.0, RFB installs cleanly:

Gofer new
    smalltalkhubUser: 'PharoExtras' project: 'RFB';
    package: 'ConfigurationOfRFB';
    load.
(ConfigurationOfRFB project version: #stable) load.

However, running the VNC Server GUI results in "MessageNotUnderstood: UpdatingMenuItemMorph>>wordingProvider:wordingSelector:".

Never mind, let's run it programmatically:

RFBServer current
    initializePreferences;
    configureForMemoryConservation;
    allowEmptyPasswords: false;
    setFullPassword: 'abc123'; "Clear text passwords..."
    setViewPassword: 'abc123456!'; "... urgh!"
    enableLogging: true;
    enableDebugging: true;
    start: 0.

RFBServer current isRunning.  true

Start the Pharo VM process (on an X-less Ubuntu 14.04 server):

% pharo -vm-display-none -vm-sound-none pharo.image &

Connect via COTVNC, try stuff... Wait, what, it froze? Close VNC connection, reconnect, and we have a debugger. Drag the debugger window... froze again. Close VNC connection, reconnect, and the debugger window is in the dragged-to position. The debugger window shows that, in this particular invocation of RFBFramebufferUpdateRectHeader>>unsignedShortAt:put:bigEndian:, the parameter value is a Float.

As the VNC connection keeps freezing, it was not possible to debug this remotely via VNC. So it is time to switch back to regular desktop Pharo.

After a bit of experimentation, this change in RFBFramebufferUpdateRectHeader>>bounds:type: seems to fix the problem:

bounds: aRect type: type
    "Set the contents of the receiver to represent a rectangle of the specified type."
    | left top width height aBlock |

    aBlock := [ :v | (v isFloat) ifTrue: [ v truncated ] ifFalse: [ v ] ].	
    left := aBlock value: aRect left.
    top := aBlock value: aRect top.
    width := aBlock value: aRect width.
    height := aBlock value: aRect height.

    self
        unsignedShortAt: 1 put: left;
        unsignedShortAt: 3 put: top;
        unsignedShortAt: 5 put: width;
        unsignedShortAt: 7 put: height;
        unsignedLongAt: 9 put: type

Once again, I have working VNC into Pharo running on an X-less server. Yay.

What about the clear text passwords? That's what SpsSplitPasswordStore is for:

RFBServer current
    initializePreferences;
    configureForMemoryConservation;
    allowEmptyPasswords: false;
    setFullPassword: (SpsSplitPasswordStore readFrom: 'spsrw.dat');
    setViewPassword: (SpsSplitPasswordStore readFrom: 'spsro.dat');
    enableLogging: true;
    enableDebugging: true;
    start: 0.

Pharo Headless Interactive RFB

4 November 2012

In deployment war stories, I wrote that Pharo's graphical environment is managed by MorphicUIManager, but when invoked -nodisplay, Pharo's graphical environment is managed by NonInteractiveUIManager.

I prefer running my servers without X as far as possible, so I want to have RFBServer running within the Pharo image, to be able to VNC into it.

As it turns out, modifying one method, MorphicUIManager>>onSnapshot:, gets me what I want. Here's what the method looks like in Pharo 1.4, timestamped CamilloBruni 2/13/2012 23:22, (minus comments because I don't like the way the Smalltalk syntax highlighting JS library I'm using is rendering them):

onSnapshot: resuming

  resuming ifTrue: [
    Smalltalk isInteractive ifFalse: [
      ^ self nonInteractiveManager onSnapshot: resuming ].
    Smalltalk isHeadless ifTrue: [
      ^ self headlessManager onSnapshot: resuming ]].

  SystemWindow wakeUpTopWindowUponStartup

I just needed to add tests for RFBServer, so now the method becomes like this:

onSnapshot: resuming
   	
  resuming ifTrue: [
    Smalltalk isInteractive ifFalse: [
      RFBServer server isRunning ifFalse: [
        ^ self nonInteractiveManager onSnapshot: resuming ]].
    Smalltalk isHeadless ifTrue: [
      RFBServer server isRunning ifFalse: [	
        ^ self headlessManager onSnapshot: resuming ]]].
   
  SystemWindow wakeUpTopWindowUponStartup

And now VNC into the Pharo image works, yay!

Deployment War Stories

28 October 2012

I used to run Squeak and subsequently Pharo on FreeBSD. I had the Smalltalk RFB server running within the image, and connected to the image via COTVNC (Chicken of the VNC), an OSX client. I ran Squeak/Pharo in a FreeBSD jail, and doing it this way kept the jail minimalist and tidy. No X stuff was installed.

Then I ran into some difficulty with FFI on CogVM on FreeBSD. (That's for another post.) And I was running FreeBSD 7, which EOLed. So I switched to Linux. Chose Debian 6 after trying out several distros. Similar setup as on FreeBSD: Minimalist LXC container, CogVM, RFB server in the same Pharo image that ran on FreeBSD.

Interestingly, neither COTVNC nor several other VNC clients (both within X on Linux and from OSX, including Java and native ones) worked in this setup: As far as I determined, the VNC connections were all failing because of incompatible encodings, and I tested quite a few combinations.

I wasn't interested in debugging too much, so I did the next simplest thing: Installed an Xvnc environment. So, instead of running an RFB server within Pharo, I had Pharo running within an X environment that was also a VNC server. And then all the VNC clients I was testing with worked. Not as tidy as I wanted, because now the LXC container had a whole bunch of X cruft, but hey, it was working.

But I really prefer FreeBSD. So after getting my production Linux server up and running, I went to investigate my FreeBSD CogVM FFI issue. And it turned out to be a process error on my part. I think. But that's for another post.

A note on my (fairly typical) setup: My development machine is an MBP. My development and pre-production FreeBSD and Linux servers all exist as VirtualBox or VMWare virtual machines on my MBP. The development servers have X, while the pre-production servers are meant to provide the canonical configuration for the production servers, so I run them without X, as much as possible. On FreeBSD, I have never had to run X in production. On Linux, I have the aforementioned Xvnc setup.

Anyhow, CogVM FFI FreeBSD was working again, in my development server running X. Next I tested it in my X-less pre-production server. When I invoked CogVM with "-headless", it said "cannot locate vm-display-X11" or words to that effect, even though said dynamic library was right there together with vm-display-null. I reckon that vm-display-X11 failed to locate an X environment, hence failed to load, hence the error message. Meaning, instead of -headless, I had to run -nodisplay.

So, CogVM ran -nodisplay, and COTVNC connected to it fine. Opened a workspace, typed some FFI-using code, selected the text with the mouse, pressed ESC. What's this? CogVM or Pharo crashed! PharoDebugLog recorded "SubclassResponsibility: NonInteractiveUIManager had the subclass responsibility to implement #newMenuIn:for:".

Hmmm. This didn't happen in Pharo 1.0 and 1.1, IIRC. Seems Pharo's random refactorings (heh, just kidding) changed how -nodisplay was managed between those versions and 1.4, the version I was testing.

After browsing a bit, looks like Pharo's graphical environment is managed by MorphicUIManager, but when invoked -nodisplay, even with a running RFB server, Pharo's graphical environment is managed by NonInteractiveUIManager.

One possibility to get this working is to install a minimal X environment, to run CogVM+Pharo -headless (with MorphicUIManager) instead of -nodisplay (with NonInteractiveUIManager).

But that isn't the simplest thing that could possibly work. What is? Copy & paste, of course. Specifically, I copied/pasted MorphicUIManager>>newMenuIn:for: into NonInteractiveUIManager. Ok, now pressing ESC brings up the context menu, "Do it" does, and output in the Transcript shows the expected FFI-related output.

Next I run my application's startup code in a workspace, one step of which is sending the "explore" message to the application's main instance, thus giving me a handle to said instance should I need to manipulate it, which is kinda the point of having VNC access into the image in the first place.

What's this? Crashed again! PharoDebugLog informs me "MessageNotUnderstood: NonInteractiveUIManager>>explorer:for:withLabel:" and "An attempt to use interactive tools detected, while in non-interactive mode".

Not so simple then...

(To be continued.)