Walnut/Persistent Secure Distributed Computing
From Erights
(→Persistent Secure Distributed Computing: changed case of an internal link) |
(→Example: Persistent eChat: put in the code from echat.e-awt) |
||
Line 10: | Line 10: | ||
===Example: Persistent eChat=== | ===Example: Persistent eChat=== | ||
+ | |||
+ | <code filename="echat.e-awt"><pre> | ||
+ | #!/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() | ||
+ | |||
+ | |||
+ | </pre></code> | ||
+ | |||
+ | |||
Next Section: [[Walnut/Secure_Mobile_Code|Secure Mobile Code]] | Next Section: [[Walnut/Secure_Mobile_Code|Secure Mobile Code]] |
Revision as of 04:03, 5 March 2008
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