Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Open Source

Agent Tcl

Source Code Accompanies This Article. Download It Now.


Dr. Dobb's Journal March 1997: Agent Tcl

Robert is a Ph.D. candidate at Dartmouth College. He can be contacted at [email protected]


A mobile agent is a program that can migrate under its own control from machine to machine in a heterogeneous network. In other words, an agent can suspend its execution at any point, transport its code and state to another machine, then resume execution on the new machine. By migrating to the location of an electronic resource, an agent can access the resource locally and eliminate the network transfer of all intermediate data. Thus the agent can access the resource efficiently even if network conditions are poor or the resource has a low-level interface.

Mobile agents move you away from the rigid client/server model toward a model in which programs communicate as peers and act as either clients or servers depending on their current needs. Existing applications for mobile agents include electronic commerce, active documents and mail, information retrieval, and workflow. Potential applications include most distributed applications, particularly those that must run on disconnected platforms or that must invoke multiple operations at each remote site.

Agent Tcl (available at http://www.cs.dartmouth.edu/~agent/) is a mobile-agent system under development at Dartmouth College. Agent Tcl uses the scripting language Tcl as its main language but provides a framework for incorporating additional languages. It provides migration and communication primitives that do not require you to explicitly capture state information and that hide the actual transport mechanisms, but which are low-level enough to be used as building blocks for a range of protocols. It is intended as a general environment for distributed applications, both in the Tcl/Tk community and the computing community at large. Although Agent Tcl is far from complete, it is in active use at several sites and has been used in several information-management applications.

Architecture

The Agent Tcl architecture (see Figure 1) has four levels. The lowest level is an API for the available transport mechanisms. The second level is a server that runs at each network site. The tasks performed by the server include:

  • Keeping track of the agents running on its machine and answering queries about their status.
  • Accepting incoming agents, authenticating the identity of their owners, and passing the authenticated agent to the appropriate interpreter. The server selects the best transport mechanism for each outgoing agent.
  • Providing a flat namespace for agents and allowing agents to send messages to each other within this namespace. Each name includes the network location of the agent. The server buffers incoming messages and selects the best transport mechanism for outgoing messages.
  • Providing access to a nonvolatile store so that agents can back up their internal states as desired. The server restores the agents from the nonvolatile store in the event of machine failure.

All other services -- navigation, network sensing, group communication, fault tolerance, location-independent addressing, and access control -- are provided by agents. The most important service agents in the Agent Tcl prototype are resource-manager agents, which guard access to critical system resources such as the screen, network, and disk.

The third level of the Agent Tcl architecture consists of an interpreter for each available language. I say "interpreter" because most languages will likely be interpreted for portability and security. Each interpreter has four components: the interpreter itself; a security module that prevents an agent from taking malicious action; a state module that captures and restores the internal state of an executing agent; and an API that interacts with the server to handle migration, communication, and checkpointing. Adding a new language involves writing the security and state-capture modules and a language-specific wrapper for the generic API. The security module does not determine access restrictions, but ensures that an agent does not bypass the resource managers or violate the restrictions imposed by the resource managers. The state-capture module must provide two functions for use in the generic API: captureState, which takes an interpreter instance and constructs a machine-independent byte sequence that represents its internal state; and restoreState, which takes the byte sequence and restores the internal state. Finally, the top level of the Agent Tcl architecture consists of the agents themselves.

Tcl and Agent Tcl

Tcl is a high-level scripting language that has several advantages as a mobile-agent language. For instance, it is:

  • Easy to learn and use due to its simplicity and an imperative style that is immediately familiar to programmers.
  • Interpreted, so it is highly portable and easier to make secure.
  • Embeddable in other applications, allowing those applications to implement part of their functionality with mobile Tcl agents.
  • Extendable with user-defined commands, making it easy to tightly integrate agent functionality with the rest of the language and allowing a resource to provide a package of Tcl commands that an agent uses to access the resource.

A package of Tcl commands can be more efficient than encapsulating the resource within an agent and is an attractive alternative in certain applications.

Tcl has several disadvantages. It is slower than native machine code. Additionally, Tcl provides no code modularization aside from procedures, which makes it difficult to write and debug large scripts. These disadvantages have not been a major hindrance since mobile agents tend to involve high-level resource access wrapped with straightforward control logic. A mobile Tcl agent is usually short even if it performs a complex task, and is usually more than efficient enough when compared to resource and network latencies. Several groups are working on structured-programming extensions to Tcl and faster Tcl interpreters.

Tcl is not suitable for every mobile-agent application, such as performing search operations against large, distributed collections of numerical data. For this reason, Agent Tcl includes a framework for incorporating additional languages. We are using this framework to add support for Java, which is much more structured than Tcl and has the potential to run at near-native speed through "just-in-time" compilation. We expect, however, that Tcl will continue to be the main agent language, and Java will be used only for speed-critical agents (or portions of agents).

The main disadvantage of Tcl is that it does not provide facilities for capturing the complete internal state of an executing script. Such facilities are essential for providing transparent migration at arbitrary points. Adding these facilities to Tcl was straightforward but required modification of the Tcl core.

The basic problem is that the Tcl core evaluates a script by making recursive calls to Tcl_Eval. The handler for the while command, for example, recursively calls Tcl_Eval to evaluate the body of the loop. Thus, a portion of the script's state is on the C run-time stack and is not easily accessible. Our solution adds an explicit stack to the Tcl core. We split the command handlers into one or more subhandlers where there is one subhandler for each code section before or after a call to Tcl_Eval. Each call to Tcl_Eval is replaced with a push onto the stack. Tcl_Eval iterates until the stack is empty and always calls the current subhandler for the command at the top of the stack. The subhandlers are responsible for specifying when the command has finished and should be popped. Figure 2 illustrates this process for the while command.

The modified Tcl core is compatible with the standard Tcl core. A command procedure that makes a recursive call to Tcl_Eval will work correctly on top of the modified core; it will just be impossible to capture the script's complete state when that command procedure is on the invocation stack. This means that existing Tcl extensions will work without modification (as long as the extension does not change the Tcl core itself). An extension has to be modified only if you want an agent to be able to carry the extension's state from machine to machine. In this case, you must make the same changes as for the while command and provide callback routines for state capture and restoration. Once the explicit stack was available, it was trivial to write procedures that save/restore the internal state of a Tcl script. These save/restore procedures are the heart of the state-capture module for the Tcl interpreter. They capture and restore the stack, procedure call frames, and all defined variables and procedures. Open files and linked variables are currently ignored.

The current implementation of Agent Tcl has two components -- a server and a modified version of Tcl 7.5 with a Tcl extension. The server, which runs at each network site, accepts, authenticates, and starts incoming agents; buffers incoming messages; provides the agent namespace; and answers queries about the status of the agents that are running on its machine. The server is implemented as two cooperating processes -- one that watches the network, and another that maintains a table of running agents.

The modified version of Tcl 7.5 provides the explicit stack and the state-capture routines. The extension provides the commands that agents use to migrate, communicate, and create child agents. The most important commands are agent_begin, agent_submit, agent_jump, agent_send, agent_receive, agent_meet, agent_accept, and agent_end. Internally each command uses the server API to contact an agent server, transfer an agent, message or request, and wait for a response. The main difference between the current implementation and the proposed architecture is that, when migrating, creating a child agent, or sending a message, the current implementation bypasses the local server and interacts directly with the destination server over TCP/IP. We adopted this approach to simplify the initial implementation, and we will change it as additional transport mechanisms are added.

An agent is simply a Tcl script that runs on top of the modified version of Tcl 7.5. The agent uses the agent_begin command to register with a server and obtain a name in the namespace. A name currently consists of the IP address of the server, a unique integer, and an optional symbolic name that the agent specifies with the agent_name command. The agent_submit command is used to create a child agent on a particular machine. agent_submit accepts a Tcl script, encrypts and digitally signs the script, and sends the script to the destination server. The server authenticates this agent, selects a name for it, and starts a Tcl interpreter in which to execute the agent. If the agent wants a symbolic name as well as a unique, integer identifier, it can call agent_name once it starts executing.

The agent_jump command migrates an agent to a particular machine. agent_jump captures the internal state of the agent, encrypts and digitally signs the state image, and sends the state image to the destination server. The server authenticates this agent, selects a new name for the agent, and starts a Tcl interpreter. The Tcl interpreter restores the state image and resumes agent execution at the statement immediately after the agent_jump.

The agent_send and agent_receive commands are used to send and receive messages. agent_meet and agent_accept are used to establish a direct connection between agents. A direct connection is a named-message stream. Direct connections are not required for communication but are more efficient and convenient. The source agent uses agent_meet to send a connection request to the destination agent. The destination agent uses agent_accept to receive the connection request and send either an acceptance or rejection. An acceptance includes a TCP/IP port number to which the source agent connects. The protocol works even if both agents use agent_meet. The agent with the lower IP address and integer identifier selects the port and the other agent connects to that port. A flexible RPC mechanism has been built on top of the direct-connection mechanism.

Agent Tcl also includes a (slightly) modified version of Tk 4.1 so that an agent can present a GUI and interact with the user of its current machine. Event handlers can be associated with incoming messages and with direct connections.

Authentication

Agent Tcl authentication is based on the Pretty Good Privacy (PGP) public-key cryptosystem. In the current implementation, we run PGP as a separate process and pipe the data to be encrypted through this process. This is clearly less efficient than tightly integrating PGP with the rest of the system, but is simpler and more flexible, especially since it becomes trivial to create an Agent Tcl distribution that does not include PGP or that uses different encryption software.

When an agent registers with a server using agent_begin, the registration request is digitally signed using the owner's private key, encrypted using the server's public key, and sent to the server. The server makes sure that the agent's owner is allowed to register on its machine and records the authenticated identity of the agent's owner. Then an IDEA secret key is used as a session key for all further communication between the agent and its newly registered server. The session key is needed to prevent a malicious program from contacting the server and masquerading as an existing agent. When the agent and its registered server are on the same machine (which is the predominant case), we do not actually encrypt with the session key since there is no possibility of message interception. A sequence number is included in the messages to prevent replay attacks.

When an agent migrates using agent_jump, it is digitally signed with the current server's private key and encrypted with the recipient server's public key. We digitally sign using the server's private key since the owner's private key is unavailable once the agent leaves its home machine. This approach requires the servers to have a high degree of trust in each other, so we will eventually adopt the Itinerant Agent solution, in which as much of the agent as possible is encrypted with the owner's private key on creation and remains encrypted throughout the agent's lifetime. The identity of the agent's owner is included in the migration message.

The recipient server chooses whether to believe the owner's identity based on its trust in the sending server. If the server accepts the agent, it records the apparent identity of the agent's owner, the authenticated identity of the sending server, and its degree of confidence that the owner's identity is valid. A session key is used for all further agent-server communication as in the agent_begin case. The same steps occur when a child agent is created with the agent_submit command except that a Tcl script is encrypted rather than a state image. The same steps also occur when an agent sends a message to an agent on another machine. In the case of a direct connection, an IDEA secret key is used as session key for all messages sent along the connection. A sequence number associated with the connection prevents replay attacks.

There are two weaknesses with the current implementation. First, there is no automatic distribution mechanism for the PGP public keys. Each server must already know all possible public keys so that it can authenticate incoming agents. An automatic distribution mechanism must be added when we start to use Agent Tcl in WANs. Second, the system is vulnerable to replay attacks in which an attacker replays a migrating agent or any message sent from one agent to another (outside of a direct connection). An obvious solution is for each server to have a distinct sequence number for all servers with which it is in contact.

Authorization and Enforcement

Once the identity of an agent's owner has been determined, the system must impose access restrictions on the agent (authorization) and ensure that the agent does not violate these restrictions (enforcement). In other words, the system must guard access to all available resources. We divide resources into two types: indirect resources accessed through another agent, and built-in resources directly accessible through language primitives for reasons of efficiency or convenience or simply by definition. Built-in Tcl/Tk resources include the screen, filesystem, wall-clock time, and CPU time.

For indirect resources, the agent that controls the resource enforces the relevant access restrictions. For each message from another agent, the local server attaches to the message a 5-tuple that contains the apparent identity of the agent's owner, the apparent identity of the sending server, a flag indicating whether the owner could be authenticated, a flag indicating whether the sending server could be authenticated, and a numerical confidence level representing how much trust the local server places in the sending server. The agent uses this 5-tuple along with its own internal access lists to respond appropriately to the incoming message. For built-in resources, security is maintained using Safe Tcl and a set of resource-manager agents. Safe Tcl is a Tcl extension that is designed to allow the safe execution of untrusted Tcl scripts. Safe Tcl provides two interpreters. One interpreter is a "trusted" interpreter with access to the standard Tcl/Tk commands. The other is an "untrusted" interpreter from which all dangerous commands (opening/writing a file and creating a network connection, for example) have been removed.

Although the dangerous commands have been removed from the untrusted interpreter, we do not want to deny all access to the resources associated with these commands. Thus, instead of removing a dangerous command entirely, Safe Tcl can replace the command with a link to a command in the trusted interpreter. This trusted command either severely restricts the functionality of the original command or examines the command arguments and the identity of the script's owner to determine if the command should be allowed. Agent Tcl uses the generalization of Safe Tcl that appears in the Tcl 7.5 core.

Agent Tcl creates a trusted and untrusted interpreter for each incoming agent. The agent executes in the untrusted interpreter. All dangerous commands have been removed from the untrusted interpreter and replaced with links to secure versions in the trusted interpreter. These secure versions check a set of access lists to see if the command is allowed. In the current implementation, there is an access list for wall-clock and CPU time, screen, network, filesystem, and external programs. Each access list is a set of (name, quantity) pairs where name specifies the name of the required resource and quantity specifies the number of instances of that resource (if applicable).

Initially the access lists are empty except that the agent is given a minimal amount of wall-clock and CPU time (our modified Tcl interpreter aborts a script if the script exceeds the time limits). To obtain additional time or to obtain access to other built-in resources, the agent must explicitly or implicitly ask a resource-manager agent for permission. There are five resource managers in the current system. These managers correspond to the five access lists and control access to wall-clock and CPU time, screen, network, filesystem, and external programs.

Our implementation does not yet provide a safe version of all dangerous commands. For example, an agent that arrives from another machine cannot use the source and send commands (the send command will probably never be available since it is difficult to make secure, and agents should communicate within the agent framework anyway). In addition, "annoyance" security threats (such as ringing the bell over and over) have not been eliminated. Agent Tcl currently protects the machine well using the simple kernel-user model of Safe Tcl. No direct access to system resources is possible. There is no way for an agent to subvert the resource-manager system since there is no way for the agent to modify the access lists contained in the trusted interpreter. It is possible for the agent to contact a resource manager directly, but this accomplishes nothing because the response will correctly grant or deny access, and, even so, will not be added to the access lists. In our case, Safe Tcl is the mechanism for enforcing the policy provided by the resource managers. When Java is added to the system, existing Java security mechanisms will be used to enforce the same policy provided by the same resource managers.

In addition to the resource managers, Agent Tcl includes a console agent. The console agent tracks all agents running on the machine and allows the machine's owner to deny entry to incoming agents and terminate running agents. It also provides a pathway through which a resource manager can ask the owner whether an agent should be able to perform a particular action. The owner will eventually be able to specify exactly those situations that require owner confirmation.

Applications

Figure 3 shows the "who" agent, which illustrates some of the agent commands. Listing One hows the Tcl source code for "who," and Figure 4 is sample output. The "who" agent's task is to determine which users are logged on to a set of machines. The agent uses agent_submit to create a child agent. The child agent jumps from machine to machine using agent_jump and executes the UNIX who command on each machine (named Bald, Cosmo, Lost-Ark, Temple-Doom, and Tuolomne). The child then sends the list back to its parent with agent_send. The parent has been waiting for the list with agent_receive and displays the list to the user. Although its task is simple and can be accomplished without a mobile agent, the "who" agent illustrates the general form of any agent that migrates through a sequence of machines.

Another example is our "alert" agent that monitors a specified set of remote resources and notifies its owner of any change in resource status. Figure 5 shows an "alert" agent that monitors a set of files and notifies users if the status of a file changes significantly (monitored characteristics include the UNIX rwx bits and the file size). Listing Two is a simplified version of the "alert" agent (the procedures file_watch, which polls the files at regular intervals using the file stat command, and construct_mail, which constructs a human-readable mail message, are not shown). The agent creates one child agent for each remote filesystem using agent_submit. Each child agent monitors one or more files in its filesystem and sends a message to the parent when the status of a file changes significantly. The parent then contacts the owner's "mail" agent to send an e-mail message.

Since the child agents know which status changes are "significant," only the status changes that the user actually wants to see are transmitted across the network. Without mobile agents, either the remote machine would have to send back a notification of every change (which the application would filter on the home machine) or the appropriate monitoring routines would have to be preinstalled on the remote machine, limiting the application to the changes that the remote administrator considers significant. With mobile agents, the application can monitor for status changes according to any desired criteria while minimizing network traffic.

A hybrid of the two examples is our text-retrieval agent that searches distributed collections of text documents. This agent is designed to be launched from a mobile device. It first obtains the query from the user and then jumps to a permanently connected machine somewhere in the network. It then spawns one child agent for each collection. The child agents travel to the remote collections, perform the query using the available retrieval tools, and return to the permanently connected machine with the query results. The original agent then discards all duplicates and carries the results back to the mobile device. This allows the agent to continue its retrieval work even when the mobile device is disconnected and minimizes the total number of bytes transferred across the low-bandwidth connection between the mobile device and the network (each document entry consists of the title, author, and abstract so it takes only a few duplicates to add up to the agent's code size). In addition, there is no need to provide high-level search operations at each collection; since the child agents move to the collections, they can perform their search efficiently even if they must combine low-level primitives into the desired search operation.

Future Directions

The first area of future work is to finish the proposed architecture. We plan to add the nonvolatile store and multiple languages and transport mechanisms (such as Lisp, Java, e-mail, and HTTP). Additionally, we plan on enhancing the resource managers and adding the security mechanisms that will protect an agent from a malicious machine and a group of machines from a malicious agent. Finally, we must extend our existing application agents so that they use the available security information.

The second area of future work is to add support agents. The resource managers that specify the security policies are one type of support agent. An effective mobile-agent system requires several more. We are in the process of identifying and constructing the necessary agents. Work on agents that provide directory services, navigation services, network-sensing tools, high-level communication services, and graphical construction tools is in progress. Some of these will be available by the time that you read this.

The third area of future work is to experimentally compare the performance of mobile agents against traditional client/server solutions and to formally characterize when an agent should remain stationary and when and how far it should migrate. Such a characterization must consider such things as network latency and bandwidth, relative machine speeds, code sizes, and data volumes.

DDJ

Listing One

  # procedure WHO is the child agent that does the jumping proc who machines { 
  global agent 
  set list "" 
    # jump from machine to machine and execute Unix who command on each machine
  foreach m $machines { 
    if {catch "agent_jump" $m"} { 
      append list "$m:\n unable to JUMP to this machine" 
    else { 
      set users [exec who] 
      append list "$agent(local-server):\n$users\n\n" 
    } 
  } 
  agent_send $agent(root) $list 
  exit
} 
set machines "bald cosmo lost-ark temple-doom moose muir tenaya tioga tuolomne"
  # get a name from the server 
agent_begin 
  # submit the child agent that jumps 
agent_submit $agent(local-ip) -vars machines -procs who -script {who $machines}
  # wait for and output the list of users 
agent_receive code string -blocking 
puts $string 
  # agent is done 
agent_end 

Back to Article

Listing Two

set email_agent "bald rgray_email"      # machine and name of email agent set machines "bald moose" 
set directory "~rgray" 
  # get a name from the server 
agent_begin  
  # submit the "file" agents that watch for changes in file size 
for each m $machines { 
  agent_submit $m -vars directory -proc file_watch {file_watch $directory} 
} 
  # wait for one of the "file" agents to send a message saying that the 
  # status of a file has changed; then send an alert message to the user 
  # by asking the user's email agent to send a message to its owner 
while {1} { 
  agent_receive code string -blocking 
  set alert [construct_alert $string] 
  agent_send $email_agent {SEND OWNER $alert} 
}

Back to Article


Copyright © 1997, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.