Walnut/Persistent Secure Distributed Computing
From Erights
Persistent Secure Distributed Computing
There is a problem with the programs we explored in the last chapter. The MarketPlace server, the RaceTrack server, and eChat are not persistent: once you shut them down they are gone forever. You can start up a new server with the same code, but it will not return to life with the same URI it had before. As a consequence, if you restart a server, you must redistribute the capability to access that server to all the users. This is a logistical nightmare. When we restart one of these servers, it must be able to restart with the same VatID and object IDs it had before.
If E simply allowed objects to remember their own URIs, there would be extensive opportunities for object forgery in the mobile code systems described in the next chapter. To prevent such forgeries, E uses swiss bases for persistence.
Swiss Bases
Example: Persistent eChat
#!/usr/bin/env rune
pragma.syntax("0.8")
# Copyright 2002 Combex, Inc. under the terms of the MIT X license
# found at http://www.opensource.org/licenses/mit-license.html ................
/**
* set up tracing; stub out all the printing for operational version
*/
def traceline(str) :void {
stderr.println(str)
}
# Ensure the user knows if he's using a clear, unencrypted connection
traceline(introducer.negotiable())
#def Title := if (introducer negotiable() == ["3DES_SDH_M"]) {
# "Secure EChat"
#} else {
# <swing:makeJOptionPane> showMessageDialog(
# null,
# "You are using DaffE, so you'll be chatting in the clear.
#To be secure, use E instead.",
# "Unencrypted DaffE Session",
# <swing:makeJOptionPane> WARNING_MESSAGE())
# "EChat"
#}
def Title := "eChat"
def chatReceiver
def sturdyChatReceiver
if (interp.getArgs() =~ [`-save`, filename]) {
throw("use persist-echat.e-awt")
} else if (interp.getArgs() =~ [`-restore`, filename]) {
throw("use persist-echat.e-awt")
} else {
traceline("once only incarnation")
introducer.onTheAir()
def [bind sturdyChatReceiver, _, _] :=
identityMgr.makeKnown(chatReceiver)
}
traceline(introducer)
traceline(sturdyChatReceiver)
/**
* return the object represented by the URI
*/
def getObjectFromURI(uri) :any {
introducer.sturdyFromURI(uri).getRcvr()
}
/**
* return the friend file
*/
def findFriendFile(chatWin) :any {
def dialog := <awt:makeFileDialog>(chatWin, "Select a Friend")
dialog.show()
var path := dialog.getFile()
if (path != null) {
path := dialog.getDirectory() + path
}
<file>[path]
}
/**
* return a file to be saved
*/
def requestSaveFile(chatWin) :any {
def dialog := <awt:makeFileDialog>(chatWin,
"Save File with Your Name",
<awt:makeFileDialog>.getSAVE())
dialog.show()
var addressName := dialog.getFile()
if (addressName != null) {
addressName := dialog.getDirectory() + addressName
}
<file>[addressName]
}
/**
* method that writes out the URI for your echat system's communication
* interface
*/
def offerMyAddress(file, uri) :void {
traceline(`$file setText("$uri")`)
file.setText(uri)
}
def set1LineComponentParameters(component) :void {
component.setPreferredSize(<awt:makeDimension>(150,25))
component.setMaximumSize(<awt:makeDimension>(1000,25))
component.setAlignmentX(0.5)
}
def chatUIMaker(chatController) :any {
# Lay out the chat window, create its components
def chatWin := <swing:makeJFrame>(Title)
def chatPane := chatWin.getContentPane()
def border := <swing:makeBoxLayout>(chatPane,1)
chatPane.setLayout(border)
traceline("p1 ui made");
def windowListener {
to windowClosing(event) :void {
chatController.leave()
traceline("trying to exit")
interp.continueAtTop()
}
match _ {}
}
chatWin.addWindowListener(windowListener)
traceline("p2 ui made");
/**
* make a button that calls the chatController
*/
def newButton(labelText, verb) :any {
# def button := <swing:makeJButton>(labelText)
def button := <swing:makeJButton>(labelText)
traceline("made button")
set1LineComponentParameters(button)
def buttonListener {
to actionPerformed(event) :void {
E.call(chatController, verb, [])
}
}
button.addActionListener(buttonListener)
traceline("button being returned")
button
}
# setNameButton
def setNameButton := newButton("Set Your Name", "setMyName")
# offerChatButton
def offerChatButton := newButton("Offer Chat", "offerSelf")
offerChatButton.setEnabled(false)
# findFriendButton
def findFriendButton := newButton("Find Friend", "findFriend")
findFriendButton.setEnabled(false)
# chatScroller that holds chatTextArea
def chatScroller := <swing:makeJScrollPane>()
chatScroller.setMaximumSize(<awt:makeDimension>(2000,1000))
chatScroller.setPreferredSize(<awt:makeDimension>(250,80))
# chatTextArea
def chatTextArea := <swing:makeJTextArea>()
chatTextArea.setLineWrap(true)
chatScroller.getViewport().add(chatTextArea)
# nextMessageBox
def nextMessageBox := <swing:makeJTextField>("Type your message here",30)
set1LineComponentParameters(nextMessageBox)
chatPane.add(nextMessageBox)
traceline("p3 ui buildt");
# sendMessageButton
def sendMessageButton := newButton("Send", "send")
sendMessageButton.setEnabled(false)
chatPane.add(JPanel`$setNameButton
$offerChatButton $findFriendButton
$chatScroller.Y
$nextMessageBox
$sendMessageButton`)
chatWin.pack()
chatWin.show()
def chatUI {
to getChatWin() :any { chatWin }
to getNameButton() :any { setNameButton }
to getOfferChatButton() :any { offerChatButton }
to getFindFriendButton() :any { findFriendButton }
to getChatTextArea() :any { chatTextArea }
to getNextMessageBox() :any { nextMessageBox }
to getSendMessageButton() :any { sendMessageButton }
}
}
/**
* facet of chatController sent to other chatter with only appropriate
* messages
*/
def chatReceiverMaker(var chatController) :any {
bind chatReceiver {
to receive(message) :void { chatController.receive(message) }
to receiveFriend(friend, name) :any {
chatController.receiveFriend(friend, name)
}
to friendIsLeaving() :void { chatController.friendIsLeaving() }
to revoke() :void { chatController := null }
}
}
/**
* @author Marc Stiegler
*/
def chatControllerMaker() :any {
def chatController := {
def chatUI := chatUIMaker(chatController)
def myChatReceiver := chatReceiverMaker(chatController)
var myName := null
var myFriend := null
var myFriendName := null
var myAddressFile := null
traceline("initialized chatController");
def showMessage(senderName, message) :void {
chatUI.getChatTextArea().append(
senderName +" says:\t"+ message + "\n")
}
def showDebug(message) :void {
# chatUI getChatTextArea() append("Debug: " + message + "\n")
}
def chatController {
/**
* transmitting functions
*/
to send() :void {
def nextMsgBox := chatUI.getNextMessageBox()
def nextMessage := nextMsgBox.getText()
nextMsgBox.setText("")
traceline("next message" + nextMessage)
myFriend <- receive(nextMessage)
showMessage(myName, nextMessage)
}
to setMyName() :void {
myName := <swing:makeJOptionPane>.showInputDialog(
"Please give me your name for this chat session")
traceline(`name: $myName`)
if (myName != null) {
chatUI.getNameButton().setLabel(myName)
chatUI.getNameButton().setEnabled(false)
chatUI.getOfferChatButton().setEnabled(true)
chatUI.getFindFriendButton().setEnabled(true)
}
}
to offerSelf() :void {
myAddressFile := requestSaveFile(chatUI.getChatWin())
if (myAddressFile != null) {
def uri := introducer.sturdyToURI(sturdyChatReceiver)
offerMyAddress(myAddressFile, uri)
}
}
to leave() :void {
if (myAddressFile != null) {
# myAddressFile delete(null)
}
myFriend <- friendIsLeaving()
chatController.disconnect("is being left")
}
to receive(message) :void {
showMessage(myFriendName, message)
}
to receiveFriend(friend, name) :any {
traceline("receiveFriend")
myFriend := friend
myFriendName := name
chatUI.getSendMessageButton().setEnabled(true)
chatUI.getOfferChatButton().setEnabled(false)
chatUI.getFindFriendButton().setEnabled(false)
chatUI.getChatTextArea().append(
myFriendName + " has arrived\n")
Ref.whenBroken(friend, def observer(prom) :void {
chatController.disconnect("disconnected")
})
traceline("received")
myName
}
to findFriend() :void {
def file := findFriendFile(chatUI.getChatWin())
if (file != null) {
def friendURI := file.getText()
showDebug("uri " + friendURI)
def friend := getObjectFromURI(friendURI)
showDebug("obj " + friend)
when (friend <- receiveFriend(myChatReceiver, myName)) ->
done(friendName) :void {
showDebug("won against all odds")
chatController.receiveFriend(friend, friendName)
} catch problem {
showDebug("clobbered: " + problem)
chatController.disconnect("is unreachable")
}
showDebug("sent me")
}
}
to friendIsLeaving() :void {
chatController.disconnect("is leaving")
}
to disconnect(desc) :void {
chatUI.getSendMessageButton().setEnabled(false)
if (myFriendName == null) {
myFriendName := "the friend"
}
chatUI.getChatTextArea().append(
myFriendName + " " + desc + "\n")
myFriend := null
myFriendName := null
myChatReceiver.revoke()
}
}
}
}
def controller := chatControllerMaker()
traceline(interp.getArgs())
interp.blockAtTop()
Next Section: Secure Mobile Code