Revision 3.0 March 1995

SOFTWARE USER'S MANUAL

FOR

KQML

(Knowledge Query and

Manipulation Language)

CONTRACT NO. F30602-93-C-01770

CDRL SEQUENCE NO. A008

Prepared for:

United States Air Force
Advanced Research Projects Agency (ARPA)

Prepared by:

Unisys Corporation
70 East Swedesford Road
Paoli, PA 19301

Table of Contents

1. Scope

1.1 Identification

This Software User's Manual (SUM) provides the procedures for utilizing the Common Lisp implementation of KQML Version 1.8 and the C implementation of KQML Version 1.95.

1.2 System Overview

1.2.1 What is KQML?

Modern computing systems often involve multiple intergenerating computations/nodes. Distinct, and often autonomous nodes can be viewed as agents performing within the overall system, in response to messages from other nodes. There are several levels at which agent-based systems must agree, at least in their interfaces, in order to successfully interoperate:

· Transport: how agents send and receive messages;

· Language: what the individual messages mean;

· Policy: how agents structure conversations;

· Architecture: how to connect systems in accordance with constituent protocols.

KQML is primarily concerned with the transport and language levels. It is complementary to work on representation languages for domain content, including the ARPA Knowledge Sharing Initiative's Knowledge Interchange Format (KIF). KQML has also been used to transmit object-oriented data. KQML is a language for programs to use to communicate attitudes about information, such as querying, stating, believing, requiring, achieving, subscribing, and offering. KQML is indifferent to the format of the information itself, thus KQML expressions will often contain subexpressions in different content languages.

KQML is most useful for communication among agent-based programs, in the sense that the programs are autonomous and asynchronous.

A KQML message is called a performative, in that the message is intended to perform some action by virtue of being sent. A substantial number of KQML performatives can be found in the Specification of the KQML Agent-Communication Language (http://www.cs.umbc.edu/kqml/kqmlspec.ps).

1.2.2 Using KQML in End-User Applications

Any programs can become KQML agents by choosing to accept messages from other programs or choosing to send messages to other programs, or choosing to do both. There is no constraint that a program be either a server or a client. Programs are viewed as agents which are free to initiate communication or respond to communication.

The KQML implementation creates additional processes to handle incoming messages asynchronously. The user's program is free to execute code or respond to local events (e.g., input from the user at the console).

1.2.3 Using the TCP/IP API

The KQML specification doesn't specify the architecture of the environment it is used in. It is possible to use KQML in a TCP/IP network of multiprocessing systems (such as UNIX workstations). But it is also possible to transmit KQML expressions over RS-232 lines or even send them via email. The agents sending them do not have to be multitasking; they can be more primitive computing systems (e.g., computers running MS-DOS). However, each implementation has to make certain assumptions about the environment in which they work.

The Unisys C and Lisp implementations are designed to work in Sun ANSI C and Lucid Common Lisp environments respectively and they assume that communication will be via a network which implements UNIX sockets.

The implementation also assumes that an agent called a facilitator will be running on an accessible and well-known host. The facilitator keeps track of which services are available and at which hosts and IP port they can be reached.

The TCP/IP primitives used by both the C and Lisp KQML implementations provide:

· A client facility for opening a connection to a remote TCP/IP service.

· A server facility which listens to multiple TCP/IP ports and transfers incoming data to a function associated with the port. It will also monitor open streams and invoke a specified function when new data becomes available.

1.3 Document Overview.

This Software User's Manual explains how KQML is implemented in Common Lisp and C and how to use this implementation to add a KQML interface to existing Common Lisp and C programs. Topics covered include

1. How to configure your local environment to run KQML.

2. How to modify an application program to utilize existing KQML services.

3. How to write a KQML agent, which is an application program that offers to answer queries and respond to assertions via KQML.

4. How to utilize the lower level TCP/IP functions included with KQML for other application programming purposes.

2. Referenced Documents

2.1 Government Documents

Software User's Manual for the Common Lisp Implementation of KQML. Contract No. F30602-91-C-0040, CDRL Seq. No. A0005

Software Design Document for the Initial Common Lisp Implementation of the KQML Knowledge Router and Knowledge Router Interface. Contract No. F30602-91-C-0040, CDRL Seq No. A006

2.2 Non-Government Documents

Mediated Information Systems Technology, http://louise.vfl.paramax.com/

Draft Specification of the KQML Agent-Communication Language, Finin, Weber, et al.

Contact Tim Finin, Computer Science, University of Maryland Baltimore County, Baltimore MD for current status. (http://www.cs.umbc.edu/kqml/kqmlspec.ps)

KQML as an Agent Communication Language, Finin, Fritzson, McKay and McEntire. The Proceedings of the Third International Conference on Information and Knowledge Management, ACM Press, November 1994. (http://www.cs.umbc.edu/kqml/papers/kqml-acl.ps)

Mediators in the Architecture of Future Information Systems, Wiederhold, IEEE Computer, vol. 25, no. 3, March 1992, pages 38-49.

3. Execution Procedures

The following sections provide instructions for setting up an environment for the successful execution of application programs, or agents, that use the C or Lisp implementations of KQML.

3.1 The KQML Lisp API

There are several steps which need to be followed to integrate and run KQML in a particular environment. These are:

· Identify functions in the local program which can be used to respond to incoming messages. Different function can be identified for each KQML performative; these can be broken down, roughly into queries , assertions and general instructions

· Identify places in the local program where it will be useful to send expressions to remote programs independently of any replies generated in response incoming messages. Insert calls to the KQML function send-msg in these places.

· Install a KQML facilitator in the local environment or identify a facilitator that is available to the local environment.

3.1.1 Configuring the KQML Architecture

The KQML specification doesn't specify the architecture of the environment it is used it. It is possible to use KQML in a TCP/IP network of multiprocessing systems (such as UNIX workstations). But it is also possible to transmit KQML expressions over RS-232 lines or even send them via email. The agents sending them do not have to be multitasking, they can be more primitive computing systems (e.g., computers running MS-DOS). However, each implementation has to make certain assumptions about the environment in which they work.

The Common Lisp implementation is designed to work in Lucid/Sun Common Lisp (Version 4) and it assumes that communication will be via a network which implements UNIX sockets.

The implementation also assumes that a single agent, called a facilitator , will be running on an accessible and well known host. The facilitator keeps track of which agents are available and which at hosts and IP port they can be reached.

3.1.1.1 Integrating Agents with Lisp KQML

To establish a KQML environment in your local area network:

· Install the KQML facilitator (See section 3.4 below) or identify a facilitator available to the local environment.

· Set the variables *local-facilitator-name* and *local-facilitator-port* in the file krouter.lisp file.

· Set the variable *local-domain* in the file tcp.lisp. (*local-domain* is set to your local internet domain name, e.g., "vfl.paramax.com". It is usually permissible to leave this field empty for purely local communications.)

The variables may be set in a separate file which loads the components of KQML, see the file config.lisp for an example of this.

3.1.1.2 Functions

(start-krouter service-name)

This function initializes local data structures and starts the KQML listener. It also registers the application under the name service-name with the local facilitator.

(stop-krouter)

Removes the applications registration with the facilitator and stops the KQML server.

3.1.1.3 Variables

*local-facilitator-name*
*local-facilitator-port*

These variables should be initialized to contain the name and port number at which the local facilitator is available. However, if they are left uninitialized the implementation will consult the UNIX environment variables FACILITATOR_HOST and FACILITATOR_PORT for this information.

3.1.2 Using KQML Services

To use KQML to query a remote service or to send a message of any kind to a remote system, you need to send a KQML message to the remote system. This is accomplished with the functions send-msg and make-msg

3.1.2.1 Functions

(make-msg performative content &rest arguments)

Constructs and returns a KQML message with the specified performative and content field and all other fields provided. A sample use is:

(send-msg (make-msg `ask-one "QUERY" :reply-with t :receiver `facilitator))

(msg-field msg key)

Returns the field identified by key in the msg

The performative of the message can be retrieved with

(msg-field message :performative).

(send-msg msg)

Delivers the msg to the appropriate host. If the msg contain a :reply-with parameter with an appropriate value then send-msg will wait for a reply and return it as the value of the function otherwise it will return NIL. Note: The value will be a message.

3.1.3 Offering KQML Services

To setup an application to respond to incoming KQML queries and assertions you only need to define and register functions which can handle the incoming message content.

3.1.3.1 Functions

(define-interface performative language)

Currently the KQML router discriminates among, incoming messages only by what their performative is and what language the content of the message is in. Use define-interface instead of defun to define a function whose only argument is bound to the variable message

For example,

(define-interface (query prolog)
(make-msg `reply
(pl-solve-all (list (msg-field message :content)))))

This expression defines a function which handles incoming queries whose content are Prolog expressions. The function uses msg-field to extract the content of the message and passes it to the function pl-solve-all and then packages the result into a new reply message.

3.1.4 TCP/IP Procedures

This section describes auxiliary routines, contained in a separate Lisp module which provide Common Lisp access to TCP/IP services. The functions support both clients and servers.

3.1.4.1 Functions

(connect-to-service hostname service &optional quiet)

Returns a bi-directional lisp stream to the remote host hostname connected to the port identified by service hostname is a string which is a hostname that can be resolved by the local operating system or is a string containing a standard form internet address (e.g., "128.126.7.41"). The service is either a string identifying a named service (i.e. something contained in /etc/services) or an integer identifying a TCP/IP port number.

The function returns NIL if a connection can not be made.

The optional Boolean argument quiet blocks the printing of error messages when a connection can not be made.

(connect hostname service &optional quiet)

Just like connect-to-service except that successive calls with the same hostname and service will return the same stream instead of opening a new one, that is, it maintains a simple connection cache.

A second Boolean returned value indicates whether the connection is a newly opened one (FALSE) or a cached one (TRUE).

(register-service function)

This function is for use in creating a TCP/IP server. It establishes a listener at the next available TCP/IP port. Connections made to this port will have their streams passed to the function which is provided as the only argument.

As a side effect, the assigned port number is stored on the property list of the function under the symbol portnum

The function provided should accept two arguments: a bi-directional stream and a host name (the name of the client initiating the connection).

(start-server)

Actually starts the TCP/IP server. No listeners are active until this function is executed. This function will also call register-service for all functions in the variable *inet-config*.

(stop-server)

Stops the listener process and closes all listener sockets.

3.1.4.2 Variables

*inet-config*

This variable contains a list of functions which will automatically be registered as listeners when start-server is called.

*local-domain*

This variable should be initialized to be the name of the local internet domain (e.g., "vfl.paramax.com" or "ai.rl.af.mil").

3.2 The KQML C API

There are several steps which need to be followed to integrate and run KQML in a particular environment. These are:

· Identify functions in the local program which can be used to respond to incoming messages. Different functions can be identified for each KQML performative; these can be broken down roughly into queries, assertions and general instructions. Register these functions with the KQML facilitator using the kqml_register function.

· Identify places in the local program where it will be useful to send expressions to remote programs independently of any replies generated in response to incoming messages. Insert calls to the KQML function kqml_send_msg in these places.

· Initialize UNIX environment variables and customize variables in KQML header files.

· Install a KQML facilitator in the local environment or identify a remote KQML facilitator which can be reached from the local environment.

· Start up the facilitator, if necessary, and the application program(s).

3.2.1 Integrating agents with C KQML

Alter your application program's makefile to include the KQML interface library (the KRIL - libkqml.a) and the KQML header file (kqml.h). Insert a call to kqml_initialize in the application, to be executed at startup.

Once you have identified the points in your program where it can respond to incoming messages, declare the functions at those points to the facilitator by inserting a call to kqml_register for each event-handling function.

Next, identify the places where messages need to be sent to a remote service. Substitute calls to kqml_send_msg, or another of the API functions used to send messages at those points.

Alter the values of the settable parameters in kqml.h, if desired.

Recompile your program, and the facilitator if you have changed values in kqml.h.

3.2.2 KQML environment variables

KQML requires that the following environment variables be defined in order to run correctly. These variables are defined in the scripts kqmlenv.csh, kqmlenv.sh and kqmlenv.tcl in the $KQML_HOME/bin directory. Each site should modify this file to suite their environment.

KQML_ANS

The host name of the machine where the facilitator is running and the port number in which it is listening for connections. The format is host_name:port_no:

KQML_HOME

The complete path to the directory where KQML has been installed.

In addition, the environment variables below may optionally be used.

KQML_WAIT_TIME

If set, the value of this environment variable will determine the default timeout (in seconds) that KRIL will wait for the return of a blocking send. If not set, the KRIL will wait for the return of a blocking send for 30 seconds.

KQML_DBG

If set, the value of this environment variable will determine the directory path in which the KRIL debug file will be stored. The file will be named agent_name.Kdbg. If not set, the stderr will be used to print the debug messages.

KQML_DBG_LEVEL

If set, the value of this environment variable will determine the amount of debugging information generated. The value ranges from 0 (Critical errors) through 9 (Verbose trace of KRIL execution). The default value is 0.

KQML_ROUTER

If set, the value of this environment variable will specify the path of the router program. If not set, the router is expected to be in KQML_HOME/bin/ or in the PATH of the agent.

3.2.3 Functions provided by the KRIL

A KQML interface library is provided for each implementation of KQML. The C KRIL defines a few functions, which are detailed below.

int kqml-initialize char *application_name ans_handler ans_lookup_function

This function initializes local data structures and starts the KQML router. It also registers the application under the symbolic name application_name with the local facilitator. The argument ans_lookup_function should be the constant KQML_NOT_AN_ANS if the agent is not an Agent Name Server, else it should be a function of type ans_handler. An application must call this function before executing any calls to kqml_send_msg. If the initialization is successful, returns 1, else -1.

int (*ans_handler) char *agent_name char **lookup_ans_name char **protocol char **addr_info

This is the prototype of the ans lookup function registered using kqml_initialize. The function looks up the address of the agent specified by the argument agent_name and returns it[[Otilde]]s protocol and address in the arguments protocol and addr_info and sets the argument lookup_ans_name to the agent[[Otilde]]s name. If this ANS does not know the address of the agent, it returns the address of another ANS which might know the address and sets the argument lookup_ans_name to the other ANS[[Otilde]]s name. Returns TRUE on success and FALSE on failure.

int kqml_register handler_function char *performative int blocking

An application calls this function at startup to tell the router what application function(s) to call when a response arrives asynchronously. This will set up an event handler. handler_function is the name of the function to be registered. The value returned by this handler function is returned to the sender of the message as the reply. If the incoming message is a blocking message, the value returned should be the actual response. For non-blocking message, the value should be an acknowledgment of receipt. performative is the kqml performative that would be handled by the handler function. If the performative is NULL, this handler function is registered as the default handler, i.e. if a performative is received for which no handler is registered, the default handler is invoked. blocking is a Boolean which is reserved for future use. Returns 1 on success, -1 on error.

void * (*handler function) char *content kqml_message *msg KQML_REPLY_TYPE *reply_type

This is the prototype of the handler function registered using kqml_register. The C-KRIL only defines the function prototype; the agent developer has to provide this function. The argument content is the pointer to the value of the content field of the received message and the argument msg is a pointer to the received KQML message. The argument reply_type is set by the handler to qualify the type of the return value and should be one of the following manifest constants:

KQML_REPLY_ERROR

Handler encountered an error while processing the message and the return value is a char pointer pointing to the error message.

KQML_REPLY_NONE

Handler has nothing to reply.

KQML_REPLY_KMSG_LIST

Return value from the handler is a linked list of KQML messages. This list can be constructed using the kqml_build_kmsg_list routine. The manifest constants KQML_HANDLER_ERROR or KQML_HANDLER_NONE can be used as a valid KMSG_LIST.

KQML_REPLY_KMSG

Return value from the handler is a KQML message. Can be constructed using the kqml_build_msg routine.

KQML_REPLY_KMSG_ARRAY

Return value from the handler is an array of KQML message with NULL as the last element of the array.

KQML_REPLY_STRING

Return value from the handler is a char pointer.

KQML_REPLY_STRING_ARRAY

Return value from the handler is an array of char pointer with NULL as the last element of the array.

KQML_REPLY_BIN

Return value from the handler is a pointer to the structure KQML_BIN_CONTENT (see description in section 3.2.5). This can be used to return binary data.

KQML_REPLY_BIN_ARRAY

Return value from the handler is an array of the structure described above with NULL as the last element of the array.

KQML_REPLY_LONG

Return value from the handler is a long pointer.

KQML_REPLY_LONG_ARRAY

Return value from the handler is an array of long pointers with NULL as the last element of the array.

KQML_REPLY_ULONG

Return value from the handler is an unsigned long pointer.

KQML_REPLY_ULONG_ARRAY

Return value from the handler is an array of unsigned long pointers with NULL as the last element of the array.

int kqml_send_msg int timeout_value char *perf char *content char *rec_agent char *reply_tag kqml_message **reply_msg ...

This function sends an expression to the appropriate destination, i.e. receiving agent using the content and the KQML performative supplied. timeout_value is the time in seconds the kqml_send _msg function wait for the reply; if the timeout_value is the manifest constant KQML_SEND_TIMEOUT, the value of the environment variable KQML_WAIT_TIMEOUT is used. perf is a KQML performative to be used as the performative of the KQML message that will be sent, content is the content message of the KQML message that will be sent, rec_agent is the name of the receiving agent that is the destination of this KQML message and reply_tag is a string to be used as the value of the :reply-with field. The fifth argument, reply_msg, is the address of a pointer to a kqml_message structure and will contain the reply to the message sent when the call to kqml_send_msg completes. The reply_tag and the reply_msg arguments should be NON-NULL if the routine should block until a result is returned, and NULL (either or both) if the routine should not block. Finally, this function allows for other arguments to be passed in, using varargs to handle this. The purpose of these final arguments is to provide the API user the ability to specify additional keyword/value pairs to be included in the KQML message sent out. If no additional keyword/value pairs are to be specified, then this argument should be NULL. Returns -1 on error. On success, if a reply is expected and if the reply is the error performative, returns 0; else returns a 1.

int kqml_send_msgv int timeout_value char *perf char *conten char *rec_agen char *reply_tag kqml_message **reply_msg char *keyword[] char *value[]

This function is identical to the kqml_send_msg function described above. The difference is that whereas kqml_send_msg allows for additional keyword/value pairs by using varargs, kqml_send_msgv allows the user to specify these keyword/value pairs using a character string array. This will be useful to users who will be calling kqml_send_msgv without knowing beforehand the number of additional arguments to be passed.

int kqml_send int timeout_vlaue kqml_message *message kqml_message **reply_msg

This function is identical to the kqml_send_msg and kqml_send_msgv functions described above. The difference is that whereas kqml_send_msg and kqml_send_msgv allows the user to specify the outgoing message by its components (keyword/value pairs), kqml_send expects the outgoing message to be a kqml_message structure.

int kqml_deliver_msg char *perf char *content ...

kqml_deliver_msg is used by an application program which is supporting the monitor and subscribe KQML performatives. Messages sent using kqml_deliver_msg will be sent to all appropriate subscribers. The KQML KRIL will automatically handle all incoming requests by clients which contain the monitor or subscribe performative. Whenever an application calls kqml_deliver_msg, the KRIL will determine which clients are listening for the information in the message and route that message to them. Returns a -1 if the message was not delivered to all the subscribers, 0 if it was delivered to some of the subscribers and 1 if it delivered to all the subscribers.

int kqml_deliver_msgv char *perf char *content char *keyword[] char *value[]

This function is identical to the kqml_deliver_msg function described above. The difference is that whereas kqml_deliver_msg allows for additional keyword/value pairs by using varargs, kqml_deliver_msgv allows the user to specify these keyword/value pairs using a character string array. This will be useful to users who will be calling kqml_deliver_msgv without knowing beforehand the number of additional arguments to be passed.

int kqml_deliver kqml_message *message kqml_message **reply_msg

This function is identical to the kqml_deliver_msg and kqml_deliver_msgv functions described above. The difference is that whereas kqml_deliver_msg and kqml_deliver_msgv allows the user to specify the outgoing message by its components (keyword/value pairs), kqml_deliver expects the outgoing message to be a kqml_message structure.

kqml_message *kqml_build_msg char *perf char *content char *rec_agent char *reply_tag ...

The kqml_build_msg function is used to construct new KQML messages. kqml_build_msg returns a pointer to a freshly allocated kqml_message structure which contains the performative and fields provided. It is not necessary to use this function to construct a message, because kqml_send_msg will construct one for you, but it is provided for programmers who are extending the KRIL or need to use the message structure for some other purpose. The perf argument is a KQML performative to be used as the performative of the new KQML message. content is the content field of the message constructed. rec_agent is the receiver of the message. reply_tag is the reply_with field of the message constructed. Additional keyword/value pairs, for inclusion in the KQML message being built, may be included after the reply_tag argument. Returns a pointer to the constructed message upon success; else NULL.

kqml_message *kqml_build_msgv char *perf char *content char *rec_agent char *reply_tag char *keyword[] char *value[]

This function is identical to the kqml_build_msg function described above. The difference is that whereas kqml_build_msg allows for additional keyword/value pairs by using varargs, kqml_build_msgv allows the user to specify these keyword/value pairs using a character string array. This will be useful to users who will be calling kqml_build_msgv without knowing beforehand the number of additional arguments to be passed.

char *kqml_get_performative kqml_message *message

kqml_get_performative returns the performative of the message.

char *kqml_get_field char *field_name kqml_message *message int *value_len kqml_expression_type *value_type

kqml_get_field returns the value of the specified field, if it exists, and NULL if no such field exists in the message. field_name is the name of the field whose value is being requested, and message is the KQML message that will be searched for that field. value_len is the length of the field and value_type is the type of the value expression. The value_type is one of the following manifest constants:

KQML_TYPE_UNKNOWN

Expression does not conform to KQML syntax.

KQML_TYPE_WORD

Expression is a KQML word.

KQML_TYPE_STRING

Expression is a KQML string (string enclosed within double-quotes).

KQML_TYPE_BYTE

Expression is a KQML byte string (string preceded by #nnÓ form). Can be used to ship binary data.

KQML_TYPE_QUOTED

Expression is a quoted KQML value (lisp quoted form).

KQML_TYPE_COMMA

Expression is a comma-quoted KQML value i.e., comma is used as the quote character instead of quote (lisp macro syntax).

KQML_TYPE_SEXPR

Expression is a KQML S-expression (equivalent to lisp s-expr).

The arguments value_len and value_type are not set if they are NULL pointers. KQML fields are identified by their associated keywords.

int kqml_get_field_count kqml_message *message

kqml_get_field_count will return the number of keyword/value pairs contained in the KQML message structure.

char *kqml_get_ith_field int field_no kqml_message *message char **field_name char **value int *value_len kqml_expression_type *value_type

kqml_get_ith_field is similar to the kqml_get_field routine described above. The difference is that whereas kqml_get_field extracts the value of a keyword (field) by its name, kqml_get_ith_field extracts it by the keyword number. Since the caller does not keyword name, the routine sets the argument field_name to point to the keyword. The argument value points to the value of the keyword, value_len is the length of the value expression and value_type is the type of the value expression. The arguments field_name, value, value_len and value_type are not set if they are NULL pointers. The keywords are indexed starting from 0. This routine is useful if the caller wants to walk through the KQML message and convert it to some other form, especially for the use of foreign language KRIL wrappers.

int kqml_put_performative kqml_message *message char *performative

kqml_put_performative will modify the performative of the KQML message if it is defined, or it will set the value, if it is not defined. Returns -1 on error, 1 if the existing performative definition was replaced, 2 if the performative was definited for the first time.

int kqml_put_field char *field_name kqml_message *message char *new_value int value_len

kqml_put_field will modify the current value of the field/keyword if that field already exists, or it will add the keyword/value pair to the KQML message, if that field/keyword does not yet exist or delete the keyword/value pair. field_name is the name of the field whose value is being changed or added or deleted, message is the KQML message to be modified with the new value, new_value is the new value of the field/keyword and value_len is the length of t new value. If the argument new_value is NULL, if a parameter with name field_name exists in the message, it is deleted. If the argument value_len argument is -1, new_value is assumed to be a C string and its length is calculated using the strlen routine. KQML fields are identified by their associated keywords. Returns -1 on error, 1 if the value of an existing field was replaced, 2 if the value of a new field was defined.

int kqml_put_embedded_msg char *field_name kqml_message *message kqml_message *embedded_msg

kqml_put_embedded_msg is similar to kqml_put_field described above. The difference is that whereas kqml_put_field accepts only a character pointer as the value of a field, kqml_put_embedded_msg accepts a KQML message structure. This is useful for constructing nested KQML messages.

KQML_KMSG_LIST *kqml_build_kmsg_list KQML_KMSG_LIST **list kqml_message *msg

kqml_build_kmsg_list adds the KQML message given by the argument msg to the end of the linked list given by the argument list and returns the list. If the argument list is NULL, a new list is created. Returns NULL on error and the modified/constructed list on success.

void kqml_free_kmsg_list KQML_KMSG_LIST *list

kqml_free_kmsg_list frees up the memory occupied by the KQML messages contained in the argument list and the memory occupied by the argument list.

void kqml_print_kmsg_list FILE *stream KQML_KMSG_LIST *list

kqml_print_kmsg_list prints the KQML messages contained in the argument list using the function kqml_print_kmsg.

void kqml_print_msg FILE *stream kqml_message *message

kqml_print_msg formats and prints the ascii representation of the KQML message structure on the given stream. Note: Currently, the printed message need not conform to KQML syntax.

char *kqml_sprint_msg char *buffer int *size kqml_message *message

kqml_sprint_msg is similar to kqml_print_msg described above. The difference is that whereas kqml_print_msg prints on to a stream, kqml_sprint_msg prints in a buffer. Further, the output of kqml_sprint_msg conforms to KQML syntax i.e it can be used as input to kqml_put_field. If the argument size is not a NULL pointer, it contains the size of the printed message upon return. If the argument buffer is NULL, the routine creates a buffer to accomodate the entire message or the argument size is expected to give the length of the buffer if it is not NULL. If the size of the buffer is not big enough to print the message, an error (NULL) is returned. Returns NULL on error and the created buffer on success.

int kqml_parse_buffer char *buffer int len int *processed_len kqml_message **message

kqml_parse_buffer parses the contents of the buffer and creates a KQML message structure from it. The argument len specifies the length of the buffer. Upon completion, the routine returns one of the following manifest constants:

KQML_PARSE_OK

Parser successfuly parsed and created a KQML message.

KQML_PARSE_EOF

Parser encountered an abnormal end of file/buffer i.e the parser encountered an end of file/buffer while parsing a message.

KQML_PARSE_NOTHING

Parser encountered a normal end of file/buffer i.e the parser encoutered an end of file/buffer before starting to parse a message.

KQML_PARSE_TIMEOUT

Parser timed out while trying read from the file.

KQML_PARSE_INCOMPLETE

Parser encountered an incomplete message; i.e while parsing, it encounted the start token of the next message.

KQML_PARSE_SYNTAX

Parser encountered syntax error; i.e the kqml message does not conform to the kqml grammar.

KQML_PARSE_SEMANTIC

Parser encounted semantic error; i.e one or more of the keywords did not start with a Ô:[[Otilde]].

KQML_PARSE_MEMORY

Parser did not have enough memory to parse the message.

and sets the argument processed_len to the number of bytes of the buffer that were consumed by the parser.

int kqml_parse_stream FILE *stream kqml_message **message

kqml_parse_stream is identical to kqml_parse_buffer described above. The difference is that whereas kqml_parse_buffer reads from a buffer, kqml_parse_stream reads from a stream.

int kqml_parse_fd int fd kqml_message **message

kqml_parse_fd is identical to kqml_parse_buffer described above. The difference is that whereas kqml_parse_buffer reads from a buffer, kqml_parse_fd reads from a file descriptor.

int kqml_timings

kqml_timings returns TRUE if timings has been enabled and FALSE if not enabled. If timings is enabled, the timings information is written to the file /tmp/agent_name.Ktime by the router.

void kqml_timings_start

kqml_timings_start enables timing functionality.

void kqml_timings_stop

kqml_timings_stop disables timing functionality.

int kqml_logging

kqml_logging returns TRUE if message logging has been enabled and FALSE if not enabled. If logging is enabled, the incoming and outgoing messages are sent to the KQML-LOGGER agent by the router.

void kqml_logging_start

kqml_logging_start enables logging functionality.

void kqml_logging_stop

kqml_logging_stop disables logging functionality.

KQML_KMSG_LIST *kqml_wrapper KQML_REPLY_TYPE reply_type void *reply

kqml_wrapper is an internal function which will almost never be called by an agent programmer. It is documented for completeness and to provide the agent developer a better understanding of the related kqml_unwrapper function. The kqml_wrapper function wraps data of different types into a KQML_KMSG_LIST data structure. The different type of data accepted by this function is documented in the explanation of the handler_function. Returns HANDLER_ERROR on error and the constructed list on success.

void *kqml_unwrapper kqml_message *msg KQML_REPLY_TYPE *reply_type

kqml_unwrapper is complementary to kqml_wrapper. It unwraps the native data from KQML message pointed to by the argument msg. The type of the unwrapped data is set in the argument reply_type. Returns NULL and sets the argument reply_type to KQML_REPLY_ERROR on error and returns a pointer to the unwrapped data on success.

int kqml_stricmp char *string1 char *string2

kqml_stricmp is similar to the library function strcmp except that it does a case-insensitive comparison.

int kqml_strincmp char *string1 char *string2 int len

kqml_strincmp is similar to the library function strncmp except that it does a case-insensitive comparison.

int kqml_digit_count long number

kqml_digit_count returns the number of digits (including the minus sign, if the number is negative) in the argument number.

int kqml_Udigit_count unsigned long number

kqml_Udigit_count is similar to kqml_digit_count except that it operates only on unsigned numbers.

int kqml_digit_to_str long number char *string

kqml_digit_to_str stores the printed representation of (similar to %d format of the library function printf) the argument number in the buffer pointed to by the argument string. It also returns the number of characters written into the buffer.

int kqml_Udigit_to_str unsigned long number char *string

kqml_Udigit_to_str is similar to kqml_digit_to_str except that it operates only on unsigned numbers.

void kqml_critical_section_start

kqml_critical_section_start blocks incoming KQML messages. This function should be called by the agent before entering a critical section of the code.

void kqml_critical_section_end

kqml_critical_section_end removes the block placed on incoming KQML message by a previous call to kqml_critical_section_start. This function should be called by the agent upon return from a critical section.

For some special queries, a wrapper for kqml_send_msg has been implemented which takes care of defining the required arguments. These special functions are defined below.

struct db_info *kqml_send_sql_query char *perf char *sql_query char *rec_agent int blocking ...

The function kqml_send_sql_query sends an SQL query to the database wrapper named by rec_agent. perf is the performative to be used in the KQML message sent out. This performative should be one that is acceptable to the database wrapper being used as the receiving agent, which, in most cases, will be ask-one or ask-all. sql_query is the database query to be executed by the remote agent/wrapper. rec_agent is the symbolic name of the database wrapper, which must be up and running for the query to succeed. This function will block, waiting for an answer if the value of blocking is TRUE, and will return immediately otherwise. kqml_send_sql_query will return a pointer to a db_info structure (see description in Section 3.5), or NULL if the query could not be executed by the remote server or if there was a problem during transmission of the query.

NOTE: Be sure that a KQML-speaking database wrapper is running for the database being accessed before calling this function.

3.2.4 Customizable KQML variables

KQMLPORT_OFFSET

The offset from port 5000 at which the KQML facilitator will listen for
connections. This variable is defined in $KQML_HOME/include/kqml/kqmllib.h

KQML_PARSER_WAIT_TIME

The number of seconds the parser will wait on a file for input before returning with a timeout error. This variable is defined in $KQML_HOME/include/kqml/kqmlparse.h

MAX_ROUTER_CONNECTIONS

The number of connections that the router can handle simultaneously. This includes the listener connection for incoming messages, the send and receive connections to the agent. This value should not be greater than number of files that a process can open (minus two for the debug file and the timing file).

3.2.5 KQML Data Structures

1. db_info would be accessed by applications which use the database wrapper, which execute calls to SAS, or which use mediators. It is used to hold query results and result table information. Its definition is in the include file db_info.h.

struct db_info {
int num_rows;
int num_cols;
int *datatype;
int *datalen;
struct u_tag **res;
}

2. u_tag, used by db_info, allows datatypes STRING or INTEGER which are the two possible types returned in a query result. Its definition is in dataconv.h.

struct u_tag {
enum dtype dtype;
union {
long ival;
char *sval;
double fval;
} u_tag_u;
}

enum dtype {
string_data_type=1,
integer_data_type=2,
float_data_type=3
}

3. KQML_BIN_CONTENT, used by handler_function, to pass binary data to the wrapper. Its definition is in kqmlwrapper.h

struct KQML_BIN_CONTENT {
int len;
void *msg;
}

3.3 Running a KQML Facilitator

The KQML facilitator is a stand-alone program, written in C, which functions as a simple database of KQML agents. It maintains a list of all active KQML agents in the local environment and is used by the router to determine the addresses of named agents that are the intended recipients of KQML messages.

Running the facilitator is simple. It is simply started in the background on a selected host. You may choose to add its startup instructions to the /etc/rc.local of a host in your environment in order to ensure that it is always running. The script for starting it up is in $KQML_HOME/bin/start_ans. The script is run as start_ans agent_name, where agent_name is the facilitator[[Otilde]]s name. The script can be passed an additional flag Ò-rÓ to enable remote shutdown of the facilitator. If remote shutdown is enabled, the script $KQML_HOME/bin/stop_ans can be used to stop the facilitator.

The start_ans and stop_ans scripts call kqmlenv.sh to setup the KQML environment variables and the path of kqmlenv.sh in these two files should be edited to match the local setup. These scripts also expect the programs anscheck and anskill to be present in the $KQML_HOME/bin directory. The source for these programs can be found in $KQML_HOME/src/examples directory.

Normally, the facilitator listens on port 5500. This can be changed by editing the file kqml.h, changing the symbolic constant KQMLPORT_OFFSET, and rebuilding the facilitator. If you do this, change the UNIX environment variable KQML_ANS to point to the new port number.

Please note that the details of the facilitator's abilities are not useful to the users of KQML since the implementation hides the transactions with the facilitator, but following is a brief description, for the C and Lisp implementations, of the KQML messages it handles.

3.3.1 Communication with KQML Facilitator using the Lisp and C API

The facilitator responds to the following KQML messages:

(tell :content (symbolic-name address-info) :reply-with t :ontology protocol)

Register the KQML agent symbolic-name as being active on the address address-info, belonging to the communication protocol protocol. The expression address-info should not contain any embedded white spaces or Ò()Ó characters. The syntax of addrerss-info for the TCP/IP protocol is of the form host:port: where host is the TCP/IP host and port is the TCP/IP port on which the agent is listening. The facilitator returns a reply performative (described below) on success and an error performative on error.

(reply :content (fully-qualified-name ans-name)
:in-reply-to t)

Currently, the fully-qualified-name is same as the symbolic-name. In the future, it will be different.

(untell :content symbolic-name :ontology protocol)

Removes the specified protocol entry for this agent from the facilitator. If no protocol is specified, all the entries for this agent is removed.

(ask-one :ontology protocol :content symbolic-name :reply-with t)

Ask for one entry in the facilitator for an agent with this symbolic-name and using the specified protocol. The facilitator responds with an error performative if there is a processing error, a sorry performative if there is no such agent or a reply performative if there is an agent with name symbolic-name and protocol. The protocol parameter can be a wild-card entry Òt, nil, null, * or emptyÓ or a list of protocols Ò(protocol1 proctocol2)Ó. In that case, the facilitator will return the first match.

(reply :ontology protocol:content Òsymbolic-name:address-infoÓ
:in-reply-to t)

(ask-all :ontology protocol :content symbolic-name :reply-with t)

Ask for all entries in the facilitator for an agent with this symbolic-name and the specified protocol. If the symbolic-name is t or ÒÓ or * or nil or null, all the entries in the facilitator that matches the specified protocol is requested. If the protocol is t or ÒÓ or * or nil or null, all the entries in the facilitator that matches the symbolic-name is requested. If the protocol is a list of protocols, all the entries that match one of the protocols and the symbolic-name is requested. The facilitator responds with an error performative if there is a processing error, a sorry performative if there is no such agent or a reply performative if there is an agent with name symbolic-name.

(reply :content ((symbolic-name-1 (protocol address-info)
(protocol address-info)) (symbolic-name-2
(protocol address-info)) ...) :in-reply-to t)

3.4 The KQML Language

Full details describing the current state of KQML can be found in the Specification of the KQML Agent-Communication Language.

KQML establishes a standard protocol and set of conventions for communication among software agent performatives which describe the type of communication being initiated (e.g., a query , an assertion , a definition , etc.)

Each expression in KQML contains a single performative and a list of parameters in the form of keyword/value pairs.

In addition, the KQML language is extensible. Though there exists a basic set of performatives (see Figure below), new performatives may be added to the specification when the need arises.

Basic query performatives:

evaluate, ask-if, ask-in, ask-one, ask-all

Multi-response query performatives:

stream-in, stream-all

Response performatives:

reply, sorry

Generic informational performatives:

tell, achieve, cancel, untell, unachieve

Generator performatives:

standby, ready, next, rest, discard, generator

Capability-definition performatives:

advertise, subscribe, monitor, import, export

Networking performatives:

register, unregister, forward, broadcast, route

There are about two dozen reserved performative names which fall into seven basic categories.

4. Errors

4.1 Errors - Lisp API

4.1.1 TCP/IP Package Errors

Many of the errors listed here do not indicate a fatal error. Because the system will retry connection attempts, the program may eventually succeed in spite of problems. These errors can be suppressed by setting the variable tcp::*krouter-suppress-warnings* to t

tcp_to_service: host <name> not found

You are attempting to reach a host whose name can not be resolved by the local name service. If you are running a Domain Name Server (DNS), it can not resolve the name. If you are running a local Network Information Service (NIS) or relying on a local host table (/etc/hosts) then the host name you are trying to reach is not in your local database.

tcp_to_service: unknown service: <service name>

You have attempted to reach a service port on a remote machine using a symbolic service name which is not known. This should not occur when using KQML since it only uses numeric port identifiers. If you are using the TCP/IP interface for another purpose, consult with you system administrator to determine why the service name you are using is not known on your system.

tcp_to_service: can't make connection: <message>
tcp_to_service: <message>

This error occurs when the system has properly resolved the host and service identifiers but is unable to make a connection with the remote system. The UNIX <message> at the end may provide additional information on why the connection can not be made. Frequently, the connection isn't made because there is no process at the remote system to accept the connection.

While trying to establish listener for: <function> on port <port>
register-service: can't make socket: <message>

While trying to establish listener for: <function> on port <port>
register-service: can't set socket option: <message>

While trying to establish listener for: <function> on port <port>
register-service: can't bind socket: <message>

These errors occurs when the system is trying to build a KQML listener and is unable to properly allocate a UNIX socket from the operating system. The <message> may give an indication of the reason.

While trying to establish listener for: <function> on port <port>
register-service: can't identify local host: <message>

This message usually signifies a problem with the local UNIX operating system.

Server not started.

The system was unable to start a KQML listener. Earlier messages are likely to have explained why.

get_connection: <message>

The system tried to accept an incoming message, but was unable to. The <message> is a UNIX system message which may explain why.

4.2 Errors - C API

When problems occur in starting up an agent or a facilitator, check the following items. For further information in diagnosing problems, consult the C-KQML Installation Manual.

4.2.1 Environment variables

Be sure that the variable KQML_HOST has been properly initialized to the complete pathname of the directory where KQML was installed.

Verify that the UNIX environment variables FACILITATOR_HOST and FACILITATOR_PORT are set. FACILITATOR_HOST should contain the name of the host where the facilitator agent is to run, and FACILITATOR_PORT should contain the port number to be used for communications. This value should be 5000 plus the number assigned to the variable KQMLPORT_OFFSET in KQML_HOST/include/kqml.h. The default value in this file is 500, therefore FACILITATOR_PORT should be set to 5500 unless you have changed the value of KQMLPORT_OFFSET.

4.2.2 Error messages

Many of the errors listed here do not indicate a fatal error. Because the system will retry connection attempts, the program may eventually succeed in spite of problems. These errors are normally written to standard error.

unable to exec router program; error #

This error occurs when the system is unable to initialize the router program for the application. The error number may give an indication of the reason.

unable to verify router is up
timed out waiting for connection
no confirmation message from router

These errors occur when the application is unable to contact the router.

unable to connect; #

This error occurs when a connection to a service cannot be opened. The error number may indicate the reason.

5. Notes

Improvements to KQML which are currently under development include the following:

· An improved facilitator including a persistent internal database and the ability to start-up certain agents if that agent is not currently available.

· An improved router including initialization of the router cache with the address information for known agents.

· A new conversation module which will insure that the KQML communication protocol is adhered to in all transactions among agents.