Koalatalk reference manual

Introduction

What is a Message Bus?

A Message Bus is a generic denomination to refer to a sytem that provides an easy way to allow communications between heterogeneous (i.e. not necessarily running on the same machine) applications that don't need to know about each other. Specifically, each application sends messages with a tag on them without knowing who will be answering its queries. Interested clients merely express interest in a set of tags somehow (1) and then listen to incoming messages, handling them as they arrive.

Koalatalk is the successor to the Koalabus ([1] [2]). For an overview of the Message Bus history, see [1]. It has been heavily inspired by SunSoft's Tooltalk ([3] [4]) for reasons that will be explained in the next section.

Why Koalatalk whereas Tooltalk exists?

Tooltalk is emerging as the leading standard, mostly due to the fact that it has been chosen for both CDE (Common Desktop Environment, <add reference here>) and COSE (Common Open Software Environment, <add reference here>).

Tooltalk introduces the notion of observers and handlers which receive messages of two types : notice messages (annoucing events) and request messages (asking operations to be performed and waiting for the results). Message addressing is very flexible : a message can be sent to a specific process, a particular type of process or a process that can perform a particular operation on an object. Messages can be object-oriented and include persistent storage and automatic activation of applications to perform object operations.

Despite these many interesting functionalities, many are cumbersome to use and sometimes half-implemented (the object part of Tooltalk is not at all compliant with the COSE specifications, and an object-addressed message is nothing more than a superset of a process-addressed message).

Thus, we felt a need to develop another Message Bus system that would meet the following criteria :

This last point showed up as the most important after a poll of KoalaBus users. A direct connection (that would bypass the server) was the most blatant lack of the KoalaBus, and of Software Buses in general. Users often found themselves having two processes communicating with each other but needing the server as an intermediary to do so.

From an architectural point of view, this direct connection may seem to be a hole in the "hiding clients" philosophy that is the starting point of the Message Bus technology. To emphasize the difference between a "regular" Message Bus (Tooltalk) and Koalatalk, we can define the following two categories :

We felt that this "point-to-point" feature was sometimes really needed and couldn't be emulated with the existing "central message passer" method (3). This accounts for the decision to give ktclients the ability to communicate with each other directly, either explicitly (kt_MessageSendToPeer()) or transparently (kt_MessageSendWithReply()), and in that latter case, Koalatalk will locate the "right" recipient for you.

The following features from the Koalabus were left out in Koalatalk :

The following Tooltalk features are present in Koalatalk :

However, most of these notions have been simplified in the process (see section Concepts).

The following Tooltalk features have not been implemented in Koalatalk :

The following section explains in details how Koalatalk works. You might want to skip directly to the section Quick start for a quick overview.

Requirements

Koalatalk can be compiled on any architecture running X11R6. It won't work on X11R5 and below (5).

Concepts

What Koalatalk is made of

"Koalatalk" refers to a set of two distinct components :

KRS and KRL

A message needs to be "tagged" in order for the Koalabus to be able to locate which recipients are eligible to receive it. Thus, each message must be accompanied with a textual string called a Koalatalk Resource Locator (KRL) (8).

On the recipient side, you have to declare a regular expresion that will be compared against the KRL's Koalatalk receives. This regular expression is referred to as a Koalatalk Resource Specification (KRS). When Koalatalk receives a message destined to a certain KRL, it matches it with all the KRS'es it knows and if a match occurs, the ktclient that declared this KRS will receive the message.

For example, a compiler might send a notice each time a compilation error is found. This notice could be sent to KRL "compiler:error". If a text editor registers its interest as an Observer in the KRS "compiler:error.*" (this is a regular expression), then it will receive all the notices emitted by the compiler.

A KRS can be seen as a "class of KRL's" : it contains all the KRL's that will be positively regexp-compared with it.

Notices and Requests

Messages are split in two categories : Notices and Requests.

Notices

A notice is a purely informative message : it is broadcast to all interested ktclients (9) to inform them about a certain information, or a state.

For example, a debugger might send a notice each time the user sets a breakpoint. This information might interest a text editor which is currently editing the source so that it highlights the line where the breakpoint is.

When you send a notice with kt_MessageSend(), it is sent to `ktserv' (which must be running) which then decides who it should be forwarded to (see below for a thorough explanation of how this resolution is performed).

Notices are sent to Observers only (i.e. who used kt_KRObserve() to register their interest).

Requests

Requests are used when a specific action is to be performed, and its result sent back to the sender. A request is sent to one Handler only, elected prealably by `ktserv' (10). However, unlike notices, requests don't go through the server : they are sent directly to a handler (if any can be found).

Actually, each ktclient has its own list of available handlers, which is kept up to date by `ktserv'. Each time a new Handler declares itself (with kt_KRHandle()), the server forwards this information to each connected client, along with the coordinates of the handler. This way, each ktclient can find the corresponding Handler without the help of `ktserv' and open a direct connection with it. This same connection will be reused if more information is exchanged between the two parts later on. All this work is transparent to the caller.

To sum up : ktclient caches some of ktserv's knowledge. Not all of it, only Handlers, since a direct connection will most likely be needed in such situations, unlike notices which can usually afford a slight overhead due to their "informative-only" nature.

If ever a request is issued and ktclient knows no handler that could handle it, several cases may arise depending on the request's mode

Observers and Handlers

You can register your interest in a KRS either as an Observer or as a Handler. Observers receive Notices, Handlers receive Requests.

Nothing is expected from an Obserer : the message is merely transmitted to it by `ktserv'. However, a Handler is a bit different in two respects :

  1. It receives the Requests directly from the Sender;
  2. A reply is expected from it (which will be sent directly to the Sender as well);

Thus, an observer implements a "procedure", or an asynchronous RPC call

Messages

Messages exchanged between ktclients have the following contents :

Note that no suppositions are made about what the message contains. If the ktclient decides to use the operation field to contain the date of the day or whatever, it is free to do so. Koalatalk won't enforce any rule on the contents, it acts merely as a message passer.

The term "Message" might be a bit misleading since it often refers to a pair "Message / KRL". When you "send a message", you actually "send a message to a KRL". Keep that point in mind.

Autostart of applications : Protocols

Sometimes, you know you may need a ktclient at one point but don't want it to be permanently connected to Koalatalk. Thus, you would like `ktserv' to launch automatically a specific program if it receives a specific message, and possibly have this ktclient quit once it has performed its task.

To achieve this, you must supply some information to `ktserv'. This information is referred to as the "protocols `ktserv' knows". The term protocols has been borrowed to the Objective C terminology ([5] [6]).

In Objective C, a Protocol is a set of certain methods an object is supposed to respond to. Sometimes, when you design an object with multiple inheritance, you usually don't want all the features of A and B, but only features X from A, and Y from B. This can be encapsulated in a Protocol.

Thus, a Protocol can be seen as a subset of messages a certain object responds to. This definition applies perfectly to Koalatalk : a ktclient needs only tell `ktserv' some of the messages it can handle/observe. If such a message reaches `ktserv', it forks the specified ktclient and forwards the message to it. This feature is very close to the "autoloading" of functions (for interpreted languages, Lips, TCL, etc...), or "dynamic loading" of libraries in compiled languages (C, C++, etc...).

Strictly speaking, the ktclient might just declare for its protocol a single message "launch_me.*" and then declare more KRS'es once it is launched. But the current implementation will let you specify an indefinite number of KRS'es in your protocol file.

A protocol file corresponds to declaring one or several KRS'es, whether they are observed or handled and an executable to fork. Just like the normal dispatching mechanism, these KRS'es will be matched against the incoming KRL of the message.

Note that the forked ktclient will still have to register a KRS matching that of the message that triggered its launching before it actually receives the message. See section Quick start, for a practical demonstration of Koalatalk usage.

See section ktserv, for a detailed explanation on how `ktserv' reads the protocols.

Quick start

This section is destined to people who compiled Koalatalk and wish to see quickly what can be done with it.

Observers

First thing to do is launch a server (13).

$ ktserv
ktserv starting pid 10558
kts_initServer: listening to 2 descriptors
Server starting on port 3661

Depending on the installation, you might see a warning from the server saying something like

*** ktserver warning : couldn't find protocol file 'protocols'

Ignore it for the moment. It is good practice to immediately set the variable $KTSERV_HOST to the host on which you just launched ktserv. Suppose `ktserv' is running on host "indri" and you want to launch ktmon on "arthur", you have to do

$ KTSERV_HOST=indri

for ksh and likes, or

$ set KTSERV_HOST indri

for csh and likes.

Now let's launch our first Koalatalk client, ktmon.

$ ktmon&

Two windows will appear, one is called MessagesW and the other one is MainW. Depending on your `app-defaults' file, you might have different default settings, so I will assume the minimum here. Logically, you will have set the -autoConnect option, either via resource (Ktmon.autoConnect: True) or with the command line (ktmon -autoConnect) (see section Utilities for more details on the syntax).

In MessagesW, set the following :

Sendto... : KRL
Destination : ko
Operation : <no op>
Message content : 1st argument, 2nd argument and 3rd argument
Notice : on

then click on the Send message push button. As soon as you do it, a message will appear in the Log (in MainW), saying something like

>>> Sent a notice to KRL:ko

Note that the symbol >>> indicates a message was sent, and <<< will mean a message was received. Apart from this message, nothing much happened, except that the server itself reacted to this message. You just sent a message to the server but since it found nobody interested in it, `ktserv' didn't forward it and threw it away.

Now let's configure our ktmon so that it receives its own message. In MainW, set

KR Spec : k.*

then click on the Add button (or press Return after typing k.*). The little list on the right of the TextField will show something like

k.* (101 o)

The 'o' means "observing" (other possible value : 'h', for "handling"). The number 101 is the ID that was given to you, Now, click on Send message in MessagesW again.

The Log now shows more information :

>>> Sent a notice to KRL:ko
<<< Observed a message, number of arguments : 3
<<< Matching id 101
        Operation : <no op>
      1st argument
      2nd argument
      3rd argument

After sending the notice, it immediately received it (as indicated by the <<< symbols). It says the received message matches the KR Spec registered under the number 101, and gives the content of this message.

You might want to launch another ktmon and make sure the messages are transmitted from one to the other if you set them properly (i.e. one observes the right KRS and the other one sends a message with the proper KRL, just like we just did. Don't worry if these names are unfamiliar right now, you don't need to understand them at this point).

Launch another ktmon and when you are convinced it is actually working, let's try direct communication.

Each Koalatalk client has a unique identity number. ktmon indicates it in the upper-left corner of MainW. It will be something like

tcp/indri:3825

This identity number may be used to open a direct communication between two `ktserv' client (but we'll see a better way to achieve that shortly). So now you have two ktmon running. Let's call the first one A and the second one B. Write down A's identity and now in B set

Send to... : Peer
Destination : A's identity

So B is sending a direct message to A. As expected, B's log says

>>> Sent message to peer

and A's log says

<<< Received direct message from a peer
        <no op>
        arg1 : 1st argument

Notice the word "direct". As you can see, when a ktclient receives a message, it can tell if it was sent directly to it by a peer, or if it was forwarded by `ktserv'.

Handlers

Now let's try to illustrate what a handler is. Quit both ktmon's and launch one again. For clarity's sake, the following examples will be shown on one ktmon only, but you might just as well use two.

A request is a message you send to "someone", and expect an answer. It might be a task you want to be performed, an information you want to retrieve, etc... Let's send a request first :

Send to... : KRL
Destination : koala
Operation : test of a request
Request : on

and click on Send message. The log faithfully acknowledges that the request has been sent, but nothing more should happen (14). This is normal, you are supposedly the only ktclient connected. Next step is to create someone who will handle this request so that we get a response. In order to do that, set the MainW with the following values

KR Spec : k.*
Handle : on

then click on Add and make sure the pattern has been registered with the flag 'h'. As soon as you do that, the log will echo

<<< Handled a message
        test of a request

and a new window will pop up. Since no handler was present when you issued your request, Koalatalk spooled it, waiting for a handler to appear. When you handled the pattern, Koalatalk recognized you as a handler for this pending request and sent it to you.

ktmon handles this by asking you what answer you wish to reply. Just fill the message as you wish (fill the three Arguments slots) and click on Send. The log confirms the reply to the request was received :

<<< Received direct message from a peer
        
        arg1 : reply

(the blank line simply indicates that the reply contains a blank Operation field. Of course, arg1 will have a different value depending on what you typed in the TextField widget...).

Protocols

Sometimes, you will want to send a request but no handler is connected to the server. In such a situation, you might want to have `ktserv' start automatically an application that can handle your request and perform the desired operation.

In order to achieve this, `ktserv' reads Protocol files when it is started (15)

We'll configure `ktserv' so that if ever a request addressed to KRL mon is sent, then it launches another instance of ktmon. The simplest way to achieve this is to edit a file called `protocol' in the same directory as `ktserv', and to put in it the following lines :

@
/u/indri/0/koala/beust/ice/koalatalk/sun4/ktmon/ktmon
handle {
  mon.*
}

Of course, you might have to modify the absolute path to reflect the location of your ktmon. Next, we must tell `ktserv' that its protocol files have been changed. To do that, find the process id of `ktserv' (16) and send the following signal (USR1):

kill -USR1 <ktserv id>

Then `ktserv' will display something like

Rereading protocol files

You can ask `ktserv' what protocols are currently know with the USR2 signal :

kill -USR2 <ktserv pid>

which causes `ktserv' to display

Known protocols :
--------------------------------------------------
/u/indri/0/koala/beust/ice/koalatalk/sun4/ktmon/ktmon
   handling 'mon.*'

Now that `ktserv' knows how to create the right KRL, fill MessagesW as follows :

Send to... : KRL
Destination : mon
Operation : <no op>
Request : on

Shortly afterwards, another ktmon should pop on your screen. But we are only halfway : whatever happened to the request? The new ktmon didn't receive it, so how is it supposed to perform the task we expect from it?

All you have to do is ask the new ktmon to declare itself as a handler with the following settings in MainW :

KR Spec : mon.*
Handle : on

and suddenly, the request will be forwarded to it and you can reply to it, just like you did a few minutes ago.

A time server

The distribution comes with a program called handletime in the `src/handletime/' directory. Add the following protocol to `ktserv' :

@
/u/indri/0/koala/beust/ice/koalatalk/sun4/handletime/handletime
handle {
  get_time.*
}

(don't forget to modify the path accordingly). This program handles requests addressed to the KRL get_time and will reply by setting the first argument to the current date. To try it, set MessagesW with the following values :

Sent to... : KRL
Destination : get_time
Operation : <no_op>
Request : on

and Send it. Within the time taken by `ktserv' to launch `handletime', you should receive the following reply :

>>> Sent a request to KRL:get_time
<<< Received a reply to request 
        time
        arg : Tue Aug 16 15:06:40 1994

Using the API

Initializing and closing a session

Use respectively kt_Init() and kt_UnInit() to start and end a Koalatalk session :

Kt_Context context = kt_Init(0, 0, 0, 0);
...
kt_UnInit(context);

kt_Init() will initialize the "direct" file descriptor. As soon as kt_Init() is finished, any Koalatalk client can send you a direct message (17). If you are interested in direct messages (you can choose to ignore them), use kt_PeerAddMsgCallback() with the appropriate callback (see below).

The parameters given to kt_Init() are used when you wish to perform multiplexed input on several file descriptors (see section API reference and section Frequently Asked Questions section about this).

Finding a server

If you don't have a server running and want Koalatalk to find one for you, you can use the function kt_LocateServer(). It returns an array of possible servers and it is your task to try each them in turn in order to find a valid one (see section ktserv).

char **servers;
int n;

kt_LocateServer(& servers, & n);
printf("%d possible servers, first one : '%s'\n", n, servers[0]);

Connecting to a server

If you need to connect to a server (but you don't have to, you might simply want to be a handler that will be contacted directly), use the following call :

   if (KT_OK == kt_OpenServerConnection(context, coord, "test")) { ...

Once this is done, you can register KRS, broadcast notices or issue requests.

Messages

Messages are created an destroyed with the function kt_MessageNew() and kt_MessageFree(). One you created a message, you can change or consult its following opaque fields : operation (kt_MessageOperationGet() and kt_MessageOperationSet()) and arguments (kt_MessageStringAdd(), kt_MessageStringGet(), kt_MessageBytesAdd(), kt_MessageBytesGet()). If you need to duplicate a message, use kt_MessageCopy().


msg = kt_MessageNew();
kt_MessageOperationSet(msg, "edit");
kt_MessageStringAdd(msg, "ktmon is dying");
kt_MessageFree(msg);

...

char *str;
kt_MessageStringGet(msg, 1, & str);  /* get 1st argument */
free(str);

Koalatalk Resources

Before sending a message, you must specify to which Koalatalk Resource Locator (KRL) it is destined. kt_KRLNew() and kt_KRLFree() serve this purpose :

Kt_KRL aKRL;
Kt_Message aMsg;

aKRL = kt_KRLNew(context, "debugger");
kt_MessageSend(context, krl, msg);
kt_KRLFree(krl);

If on the other hand you wish to declare your interest in a Koalatalk Resource, use kt_KRObserve() or kt_KRHandle() :


void
cbObserve(Kt_Context context, void *userData, Kt_Message msg, CARD32 id)
{...}

...
CARD32 krs;

krs = kt_KROBserve(context, "edit.*", cbObserve, globalVars);

The value returned by both calls is a CARD32 number that will be passed on to the specified callback when you receive a message destined to a KRL matching the specification you supplied.

For example, suppose krs receives the value 101, and a little later someone sends a message to the KRL "editor", the function cbObserve will be called with its parameter id equal to 101.

Callbacks

There are several types of callbacks understood by Koalatalk, they all have one of the following two signatures :

void
cb1(Kt_Context context, void *userData, Kt_Message msg)

or

void
cb2(Kt_Context context, void *userData, Kt_Message msg, CARD32 id)

The only difference is in the last parameter. It is needed only if the callback has been called because it matched a prealable call to the API. This includes :

The only case where you don't need to receive an id in parameter is when a peer is sending you a direct message (as soon as you call kt_Init(), you listen to a special "direct" file descriptor which any other Koalatalk client can use to contact you directly).

Sending messages

Once you have both a message (Kt_Message) and a recipient (Kt_KRL), you are ready to send a message. You have the following alternatives :

There is an addional function in the API, called kt_MessageSendOnExit() that will allow you to store an "emergency" message in the server (along with a KRL). This message will be sent by the server if ever you die unexpectantly (i.e. you didn't close your connection to the server by a call to kt_CloseConnection()).

API reference

Types

Type: Kt_CallbackHandlerMsg

void *
cbHandler(Kt_Context ktContext, void *userData, Kt_Message msg, CARD32 id)

This must be the type of the callback used as parameter for kt_KRHandle(). msg will contain the message sent to you and id is the identity that was issued when you called kt_KRHandle(). userData has the same value as the one supplied in kt_KRHandle().

Type: Kt_CallbackPeerMsg

void *
cbDirect(Kt_Context ktContext, Kt_Message msg)

This must be the type of the callback used as parameter for kt_PeerAddMsgCallback(). This callback will be called each time a peer sends a message directly to you.

Type: Kt_CallbackReplyMsg

void *
cbReply(Kt_Context ktContext, void *userData, Kt_Message msg, CARD32 id)

This must be the type of the callback used as parameter for kt_MessageSendWithReply(). msg will contain the message sent to you and id is the identity that was issued when you called kt_MessageSendWithReply(). userData has the same value as the one supplied in kt_MessageSendWithReply().

Type: Kt_CallbackServerMsg

void *
cbObserve(Kt_Context ktContext, void *userData, Kt_Message msg, CARD32 id)

This must be the type of the callback used as parameter for kt_KRObserve(). This callback will be called each time a peer sends a message directly to you.

Type: Kt_CallbackAddInput

void *
addInput(int fd, void *userData)

This must be the type of the callback used as parameter for kt_Init(). This callback will be called by Koalatalk when it wants you to add one of its file descriptor to the set. userData is usually a variable that belongs to you and allows you to retrieve this "global file descriptors set".

Type: Kt_CallbackRemoveInput

void *
removeInput(int fd, void *userData)

This must be the type of the callback used as parameter for kt_Init(). This callback will be called by Koalatalk when it wants you to remove one of its file descriptor from the set. userData is usually a variable that belongs to you and allows you to retrieve this "global file descriptors set".

Type: Kt_Context

A Koalatalk context.

Type: Kt_Disposition

When a request is sent and no handler can handle it at the moment, this type is used to specify how Koalatalk should react. It is an enumerate type of

Type: Kt_KRL

A Koalatalk Resource Locator.

Type: Kt_Message

A message.

Type: Kt_PeerConnection

A peer connection.

Type: Kt_Status

This is the type returned by most of Koalatalk's API calls. It is an enumerate type of

Functions

Function: void
kt_AddUserFileDescriptor
(Kt_Context context, int fd, void (*callback)(), void *userData);

Add a user file descriptor. The specified callback will be called if ever data on this fd is ready. The callback will receive userData as its unique argument.

Function: Kt_Status
kt_CloseConnection
(Kt_Context context);

Close a connection to the server.

Return : KT_OK if successful, KT_ERR otherwise.

Function: void
kt_NextMessage
(Kt_Context context, Kt_Message *msg);

Call the appropriate callbacks for msg.

Return : True if at least a callback was called, False otherwise.

Function: void
kt_HandleInput
(Kt_Context context, fd_set fds);

When you are managing your own main loop (i.e. you do the select() yourself), you have to call this function if ever a file descriptor that belongs to Koalatalk is active.

Function: Kt_Context
kt_Init
(Kt_CallbackAddInput addInput, void *addInputUserData, Kt_CallbackRemoveInput removeInput, void *removeInputUserData)

Initialize Koalatalk.

If you wish to monitor personal file descriptors in addition to Koalatalk's, you have to supply values to addInput and removeInput. If you do this, Koalatalk will rely on you to

Return : a Koalatalk Context, to be used in subsequent calls.

Function: CARD32
kt_KRHandle
(Kt_Context context, char *krs,Kt_CallbackHandlerMsg callback, void *userData);

Declare as a handler for a Koalatalk Resource. callback will receive the message in argument, it must not free it (it will be automatically freed by the toolkit). krs is the Koalatalk Resource Specification to be handled (a regular expression).

Return : (CARD32) 0 if failure, or a unique identity number that will be passed on to callback each time a message matching krs is received.

Function: void
kt_KRLFree
(Kt_KRL krl)

Free the memory allocated in krl.

Function: Kt_KRL
kt_KRLNew
(Kt_Context context, char *krlName);

Define a Koalatalk Resource Locator with name krlName.

Return : A valid KRL (which must be free()'ed when no longer needed).

Function: CARD32
kt_KRObserve
(Kt_Context context, char *krs, Kt_CallbackServerMsg callback, void *userData);

Declare as an observer for a Koalatalk Resource. callback will receive a msg in argument, it must not free it (it will be automatically freed by the toolkit). krs is the Koalatalk Resource Specification to be observed (a regular expression).

Return : (CARD32) 0 if failure, or a unique identity number that will be passed on to callback each time a message matchine krs is received.

Function: Kt_Status
kt_KRUnObserve
(Kt_Context context, CARD32 krId);

Stop observing the Koalatalk Resource krId (value returned by a call to kt_KRObserve().

Return : KT_OK if successful, KT_ERR otherwise.

Function: void
kt_LocateServer
(char ***serversFound, int *serversFoundCount)

Try to locate a server. serversFoundCount will contain the number of servers that could be found, or 0 if Koalatalk can't even make a guess. You will find the coordinates to try in serversFound[0..serversFoundCount-1], which you can pass directly to kt_OpenServerConnection().

Note : this is just a guess, the coordinates returned might correspond to a dead server anyway.

Note 2 : each string serversFound[i] must be freed by the caller afterwards, and serversFound itself as well eventually

Function: void
kt_MainLoop
(Kt_Context context);

Main loop to process messages and invoke callbacks accordingly.

Function: Kt_Message
kt_MessageArgCount
(Kt_Message msg);

Return : the number of arguments in msg (first argument is number 0).

Function: Bool
kt_MessageArgIsString
(Kt_Message msg, int argPos);

Return : True if argument number argPos is of type String (note that the first argument is number 0).

Function: Kt_Status
kt_MessageBytesAdd
(Kt_Message msg, void *bytes, size_t len);

Add a bytes parameter to a message.

Return : KT_OK if successful, KT_ERR if error.

Function: Kt_Status
kt_MessageBytesGet
(Kt_Message msg, int argPos, char **returnedBytes, size_t *returnedLength);

Retrieve the argPos'th argument of this message, which must be of bytes type. Note : returnedString must be freed with free() when no longer needed. Argument 0 is the first argument.

Return : KT_OK if successful, KT_ERR if argument type is not bytes.

Function: Kt_Message
kt_MessageCopy
(Kt_Message msg);

Allocate a new message, copy the content of msg into it and return it.

Return : a copy of msg (which can be safely freed with kt_MessageFree() afterwards without interfering with the returned argument). Note : duplicating a message with a simple assignment will not work. If the duplicated message is freed, the copy you hold will become invalid as well.

Function: void
kt_MessageFree
(Kt_Message msg);

Free a message.

Function: Kt_Message
kt_MessageNew
();

Allocate a new message.

Return : an empty message.

Function: Kt_Status
kt_MessageOperationGet
(Kt_Message msg);

Return : the operation field for this message. Note : the returned value must not be altered. It is a direct pointer to Koalatalk's internal space. Argument 0 is the first argument.

Function: Kt_Status
kt_MessageOperationSet
(Kt_Message msg, char *operation);

Set the operation field for this message.

Return : always KT_OK. Note : the string is duplicated in Koalatalk's internal space, you can free it immediately after this call.

Function: Kt_Status
kt_MessageReply
(Kt_Context context, Kt_Message query, Kt_Message reply);

Reply to the request request. reply is sent directly to the sender.

Return : KT_OK if the reply was sent successfully, KT_ERR otherwise.

Function: Kt_Status
kt_MessageSend
(Kt_Context context, Kt_KRL krl, Kt_Message krl);

Send a message to a Koalatalk Resource Locator, prealably defined by a call to kt_KRLNew(). This message can be seen as a notice, since it might reach several ktclients and no reply is expected.

Return : KT_OK if the message was sent successfully, KT_ERR otherwise.

Function: void
kt_MessageSendOnExit
(Kt_Context contex, Kt_KRL krl, Kt_Message msg);

Ask the server to store this message and to send it (just like if sent with kt_MessageSend()) if ever it loses its connection to me some other way than by kt_CloseConnection().

Return : KT_OK if the message was stored successfully, KT_ERR otherwise.

Function: char *
kt_MessageSender (Kt_Message msg);

Return : the sender (ICE coordinates) of current message. This function *can* return an empty string (but never NULL), since kt_MessageNew() is invoked without any Kt_Context in it, and is therefore a "standalone" function. Do not modify or free the returned value, it belongs to Koalatalk.

Function: Kt_Status
kt_MessageSendToPeer
(Kt_Context context, char *peer, Kt_Message msg);

Send msg to peer identified by peer, a string that contains valid ICE coordinates (e.g. tcp/indri.inria.fr:2592).

Return : KT_OK if msg was sent successfully, KT_ERR otherwise.

Function: CARD32
kt_MessageSendWithReply
(Kt_Context context, Kt_KRL krl, Kt_Message msg, Kt_Disposition disposition, Kt_CallbackHandlerMsg callback, void *userData);

Send a message and expect a reply.

Return : (CARD32) 0 if failure, or a unique identity number that will be passed on to callback each time a message matchine krs is received.

Function: Kt_Status
kt_MessageStringAdd
(Kt_Message msg, char *string));

Add a string parameter to msg.

Return : KT_OK if successful, KT_ERR if error.

Function: Kt_Status
kt_MessageStringGet
(Kt_Message msg, int argPos, char **returnedString);

Retrieve the argPos'th argument of msg, which must be a string. Note : returnedString must be freed with free() when no longer needed.

Return : KT_OK if successful, KT_ERR if argument type is not a string. If something wrong occured, returnedString will be an empty string.

Function: void
kt_NextMessage
(Kt_Context context, Kt_Message *msg);

Return : the next message received from Koalatalk (msg will be allocated by the toolkit, you need not call kt_MessageNew()).

Function: kt_Status
kt_OpenServerConnection
(Kt_Context context, char *serverLocation, char *identity);

Open a connection to the server specified by id (possibly obtained from a call to kt_LocateServer().

Return : KT_OK if connection could be opened successfully, KT_ERR otherwise.

Function: Kt_PeerConnection
kt_PeerOpenConnection
(Kt_Context context, char *{peerLocation});

Open a direct connection to a peer. peerLocation is a string that contains valid ICE coordinates (e.g. tcp/indri.inria.fr:2592).

Return : An identifier to be used to send messages directly to this peer.

Function: IceConn
kt_PeerReturnIceConnection
(Kt_PeerConnection peer);

Return : The IceConn descriptor for this connection.

Function: int
kt_PeeReturnIceProtocol
(Kt_PeerConnection peer));

Return : The ICE protocol used to talk with this peer.

Function: IceConn
kt_ReturnIceServerConnection
(Kt_Context context);

Return : The IceConn descriptor of the server.

Function: int
kt_ReturnIceServerProtocol
(Kt_Context context);

Return : the protocol used to talk with the server.

Function: char *
kt_ReturnIdentity
(Kt_Context context);

Return : a string containing my identity. Note : do not modify this string, it is a pointer to Koalatalk's internal name space.

Function: void
kt_SetServerErrorHandler
(Kt_Context context, void *handler);

Define the handler to be called if the connection to the server is lost.

Function: void
kt_UnInit
(Kt_Context ktContext)

Uninitialize Koalatalk

Utilities

ktmon

`ktmon' stands for Koalatalk Monitor. It is a tool that lets you play with the Koalatalk without the hassle of writing an application and going through the process of compilation for simple examples. Its syntax is the following :

$ ktmon -help
Usage : ktmon
                -autoConnect
                -observed <value>
                -handled <value>
                -sendToKRL
                -isNotice
                -krl <value>
                -arg1 <value>
                -arg2 <value>
                -arg3 <value>
                -operation <value>
                -server <value>

Each of these keywords has its equivalent as a resource. As a standard Motif application, `ktmon' will read its application defaults in the usual places. Its class name is Ktmon (19).

These parameters allow you to set certain values on startup, they are all facultative.

ktserv

Syntax


$ ktserv -help
Usage: ktserv 1.1beta
        [-help]                 This help
        [-debug <n>]            Set debug level
        [-icedebug]             Turn on ICE debugging

Environment variables

`ktserv' uses/consults the following environment variables :

Signals

You can use `kill' on `ktserv''s process with the following signals :

Files

How the server advertises its presence

As of current version (1.34beta), when `ktserv' is launched, it will store its coordinates in the following places :

Frequently Asked Questions

How do I integrate a Koalatalk application and an X application?

Since Koalatalk handles several file descriptors, the usual method (XtAddInput()) is not appropriate here, so a slightly more complex scheme has to be used. In such a case, Koalatalk will rely on you to handle the set of file descriptors, but it needs to know what function (belonging to you) it has to call each time it wants to add or remove a file descriptor from this set. This information is supplied with kt_Init().

A typical section (syntaxically incorrect, but you get the idea) of code to replace XtMainLoop() would be :


static void
busAddInput(int fd, void *userData)
{
   GV gv = (GV) userData;
   FD_SET(fd, & gv -> fds);
}

static void
busRemoveInput(int fd, void *userData)
{
   GV gv = (GV) userData;
   FD_CLR(fd, & gv -> fds);
}

void
guiHandleXInput(GV gv)
{
   XtInputMask xim;
   XEvent event;

   while (0 != (xim = XtAppPending(gv -> appContext))) {
      XtAppNextEvent(gv -> appContext, & event);
      XtDispatchEvent(& event);
   }
}

int
main()
{
   context = kt_Init(busAddInput, gv, busRemoveInput, gv);
   gv -> xfd = XConnectionNumber(XtDisplay(toplevel));
   FD_ZERO(& gv -> fds);

/* Add your own file descriptors */
   busAddInput(gv -> xfd, gv);

/* Koalatalk will add its file descriptors silently */

   while (1) {     /* this is the main loop */
      int ready;
      fd_set fds = gv -> fds;
      ready = select(kt_getdtablesize(), & fds, 0, 0, 0);
      if (ready > 0) {
         if (FD_ISSET(gv -> xfd, & fds))   /* an X event */
            guiHandleXInput(gv);
         else
         kt_HandleInput(gv -> ktContext, fds);   /* a Koalatalk event */
      }
   }


References

[1] The KoalaBus Group Communication Software, Programmer's manual
Cedric Beust, Colas Nahaboo, 1992

[2] Making applications cooperation easier : The KoalaBus experience
Cedric Beust, 1993

[3] Introduction to the Sunsoft's Tooltalk Service
A White Paper by Ricki Franker, 1991

[4] Tooltalk's Programmer's Guide
Sun Microsystems, December 1992

[5] Object Oriented Programming, an evolutionary approach
Brad J.Cox, 1986

[6] Objective C, Object-oriented programming techniques
Lewis J. Pinson, Richard S.Wiener, 1991

Concept Index

-

  • -autoConnect

    a

  • Arguments
  • Arguments of a message

    b

  • bytes

    h

  • Handler

    k

  • kill
  • Koalatalk Resource Locator
  • Koalatalk Resource Specification
  • KRL
  • KRS
  • ktserv pid

    o

  • Objective C
  • Observer
  • Operation
  • operation
  • Operation of a message

    p

  • pid
  • Protocol
  • Protocol files

    s

  • SIGUSR1
  • SIGUSR2

    u

  • USR1
  • USR2