@c -*-texinfo-*-
@node Mailboxes, Foreign Interface, Tcp, Top
@comment  node-name,  next,  previous,  up
@chapter Mailbox-based communication model
@cindex mailbox
@menu
* MbxIntroduction::             Introduction to Mailboxes
* MailboxServer::               Mailbox Server
* RestrictedAccess::            Restricting Access
* StartingMailboxes::           Starting Mailboxes
* MailboxPrimitives::           Mailbox Primitives
@end menu

TCP works well for applications which
naturally map onto the client-server model.  There is an asymmetry
between the clients and the server.  However, in the simple case of
two processes having a conversation, it seems to be an unnecessary
overhead and confusing complication to force one process to be the
server and somehow provide a service to the client, when it is much
more natural to think of them as two symmetrical processes.

In TCP, the instrument of communication is a socket.  A socket is one
end of a communication channel.  To set up a channel between a server
and a client, two sockets are created (one by the server and the
other by the client) and are then connected to each other.  This is
analogous to a telephone conversation where two telephones are
required to set up a connection.  As with telephones, TCP
communication is strictly one-to-one.  There are no facilities to set
up one-to-many or many-to-one conversations.

In TCP, every communication channel set up between a server and a
client is a separate network connection.  The system overheads of
creating sockets and setting up connections over the network become
significant if the conversations are short and there are many such
conversations.  For example, if ten processes on one machine are
talking to ten processes on another machine, there will be ten
network connections between the two machines.

These disadvantages can be overcome by providing a higher level
abstraction that is more powerful and simpler to use.  Mailboxes
provide such an abstraction.

This section documents the Mailbox primitives.  These primitives
are available to both the Prolog and Parlog sub-systems of ICP.
The Mailbox interface is not part of the core ICP system and must be loaded
by a command of the form
@example
?- ensure_loaded(mailbox).
@end example
The Prolog and Parlog interfaces are distinct libraries and so must be
loaded separately.

Note that only the `blocking' form of the mailbox primitives are currently
implemented.

@node MbxIntroduction, MailboxServer,  , Mailboxes
@comment  node-name,  next,  previous,  up
@section Introduction to Mailboxes
In the mailbox model, the instrument of communication is a mailbox.
A mailbox is simply a repository for messages.
Mailboxes may be created freely by any process.
Messages can be sent
to and removed from a mailbox.  Instead of having
to create two sockets to communicate, we now need to create only
one mailbox.  For two processes to communicate, the sender
places a message in the mailbox, and the receiver removes it from
the same mailbox.  A mailbox can store multiple messages.  Messages
are kept in arrival order so that it naturally simulates stream
communication.

@menu
* MessagePeeking::              Message Peeking
* TwowayCommunication::         Two-way Communication
* MultiwayCommunication::       Multi-way Communication
@end menu

@node MessagePeeking, TwowayCommunication,  , MbxIntroduction
@comment  node-name,  next,  previous,  up
@subsection Message Peeking
When a message is read from a mailbox, there is an option to
not remove it.  The message can remain in the mailbox.  This
is so that a receiving process can determine whether it should
be left for another process to handle.  This can occur because
multiple processes may be reading from the same mailbox.  When
a message is being checked in this way, further reads from this
mailbox must wait until a decision has been made regarding the
message.  The options are to commit the read and remove the
message, or to discard the read and leave it in the mailbox.

@node TwowayCommunication, MultiwayCommunication, MessagePeeking, MbxIntroduction
@comment  node-name,  next,  previous,  up
@subsection Two-way Communication
Messages in a mailbox may be read by any process, including the
process that sent it.  This makes it difficult (though not
impossible) to implement two-way communication using only one
mailbox.  Mailboxes are best used when only one receiver reads
messages from it.  Since there is very little cost associated
with creating new mailboxes, two-way communication should be
carried out using two mailboxes.

@node MultiwayCommunication,  , TwowayCommunication, MbxIntroduction
@comment  node-name,  next,  previous,  up
@subsection Multi-way Communication
A link may be established between two mailboxes.  When a message
is sent to the first mailbox, the message is automatically
forwarded to the second mailbox.  Note that the link is
uni-directional only - messages sent directly to the second mailbox
will not by forwarded to the first.  The second mailbox remains
an ordinary mailbox while the first becomes a `linked' mailbox.
Linked mailboxes do not store any messages, only addresses of
links.  A mailbox may be linked to many mailboxes.  In this
case, messages sent to the linked mailbox will cause a copy
of the message to be forwarded to each and every link.  This
is how we can configure one-to-many communication.  Note
that there is a distinction between the case where multiple
receivers each receive copies of all messages, and the case
where only one of the multiple receivers receive each message.
In the former case, we can use linked mailboxes but in the
latter case, one mailbox is sufficient.

Many-to-one communication can also be configured by linking
multiple mailboxes to the same mailbox.  Indeed, any
arbitrary communication topology may be built up using 
links.

If a mailbox is linked to another mailboxes while some messages are stored in
it (waiting to be read), the messages will be kept until the mailbox is 
unlinked or closed. If is unlinked, the messages will be accessible again.

@node MailboxServer, RestrictedAccess, MbxIntroduction, Mailboxes
@comment  node-name,  next,  previous,  up
@section Mailbox Server
All the above pre-supposes that a mailbox can be uniquely
identified in a network and can be accessed by all machines
on the network.  This can be guaranteed by ensuring that
when a mailbox is created, the identifier returned is a
combination of the process number and the number of the
mailbox in that process.  The process number is allocated
by an external mailbox server program.  Note that the
process number is a generalisation of the machine number
since a machine may run many processes.

When a process requires the use of mailboxes, it first 
registers with the mailbox server which allocates a process
number to it.  The mailbox server replies by sending the
process numbers and physical network addresses of all the
other registered processes.  It also notifies existing
registered processes that there is a new process.  By
keeping all processes up-to-date with this information,
processes may communicate with each other directly without
contacting the mailbox server again.  The mailbox server
does not become a bottleneck in the system and in fact
mailbox communication can continue even if the server
program is terminated.  Of course in this case, any further
changes to the registered process list will not be reflected.

Using a mailbox server, a set of processes can cooperate
and communicate with each other by registering with this
server.  The set of processes is called a @var{mailbox group}.
A completely different mailbox group can exist if there is
another mailbox server program running.  In general, there
is no limit to the number of mailbox groups.  Each group
is a completely independent system.

@menu
* RegisteringMailboxNames::     Registering Mailbox Names
@end menu

@node RegisteringMailboxNames,  ,  , MailboxServer
@comment  node-name,  next,  previous,  up
@subsection Registering Mailbox Names
In the model presented above, we can see how it would be
possible to communicate if we know the mailbox identifier.
However the bootstrapping problem of finding out the relevant
identifier still remains.

If a process is willing to accept incoming communication,
it should create a mailbox and register a name along with
the mailbox identifier.  This registration is done by
sending a message to the mailbox server program (the mailbox
server has a pre-defined address).  Thereafter, when another
process wishes to talk to the named process, it can query
the mailbox server program for the mailbox identifier.  This
is very similar to telephone directories.  The correspondence
between names and telephone numbers is stored in a telephone
directory.  If you do not know the number, you look up the
name.  The mailbox server program provides this necessary
directory lookup service.

@node RestrictedAccess, StartingMailboxes, MailboxServer, Mailboxes
@comment  node-name,  next,  previous,  up
@section Restricting Access

Restricted access can be enabled for the mailbox server and individual
 mailboxes.  This is implemented in two layers. 

The first layer is a user level restriction. At mailbox creation time, 
read and write permissions can be defined for the user, group and others.
The possible values for permissions are @code{read_write}, @code{read},
@code{write} and @code{none}.

The second layer is a process level restriction.  This filters the processes that 
pass the first layer. At mailbox creation time, a read password and/or a 
write password can be defined and every process wishing to access the mailbox 
must supply the correct password.  The passwords are actually integers.

These restrictions can be used for the mailbox server as well, restricting 
the access to the services supplied.

@node StartingMailboxes, MailboxPrimitives, RestrictedAccess, Mailboxes
@comment  node-name,  next,  previous,  up
@section Starting Mailboxes

The mailbox server is a standalone program written in C.
To use mailboxes, there must first be a mailbox server
running on the network.  A mailbox server with the mailbox
group name of @code{mbx1} is started in
the background from the Unix command line like this :
@example
        mbx_server mbx1 &
@end example
Note that this is run from Unix, not from within Prolog.
A confirmation message should appear as follows :
@example
        Server [mbx1] started on machine HOSTNAME
@end example
where HOSTNAME is the name of the machine on which
the mailbox server is running.
The program runs until it is explicitly
killed using CTRL-C.

The identifier @code{mbx1} is associated with a particular
port number in the file /etc/services.  If you get
the message
@example
        service: mbx1 not found
@end example
then /etc/services has not yet been modified.  Please
read the installation procedures on how to do this.
There are four pre-defined mailbox group names in /etc/services,
they are @code{mbx1}, @code{mbx2}, @code{mbx3} and @code{icprolog}.
You may define more if you wish by adding lines to the /etc/services
file.

When starting the server, if you get the message
@example
        error: server is already running or socket is in use
@end example
this means that the server is already running for that
mailbox group.  If however, you do not wish to participate
in an existing mailbox group, then you should start another
server using the identifiers @code{mbx2} or @code{mbx3} instead.


@node MailboxPrimitives,  , StartingMailboxes, Mailboxes
@comment  node-name,  next,  previous,  up
@section Mailbox Primitives

The Mailbox primitives described below are available to both Prolog
and Parlog components of the ICP system.

In the short forms of the primitives, the dafault values for the
arguments are user @code{read_write}, group @code{write} and others
@code{write} permissions, @code{0} read password and @code{0} write
password and they supply @code{0} as password.

@menu
* MbxInit::                     Opening, Modifying and Closing Mailboxes
* MbxIO::                       Reading and Writing from Mailboxes
* MbxMisc::                     Miscellaneous Mailbox Predicates
@end menu

@node MbxInit, MbxIO,  , MailboxPrimitives
@comment  node-name,  next,  previous,  up
@subsection Opening, Modifying and Closing Mailboxes

@table @code
@item mbx_init(@var{+Address}, @var{+MailboxGroup})
@findex mbx_init/2
Connects to server @var{MailboxGroup} on machine @var{Address}.  This
must be the first mailbox primitive to be called since this initialises
the connection.  @var{MailboxGroup} is normally one of 
@code{mbx1}, @code{mbx2} or @code{mbx3}, but it may be any string
as long as it is defined in the /etc/services file.

@item mbx_create(@var{-Mbx})
@itemx mbx_create(@var{-Mbx}, @var{+User}, @var{+Group}, @var{+Others}, @var{+RPass}, @var{+WPass})
@findex mbx_create/1
@findex mbx_create/6
This creates a mailbox, returning its global address as an identifier @var{Mbx}.
For efficiency reasons, it is more natural (although not necessary) to create 
a mailbox on the machine that the processes which are going to receive from 
it are running.

@item mbx_close(@var{+Mbx})
@itemx mbx_close(@var{+Mbx}, @var{+TimeOut}, @var{+RPass})
@findex mbx_close/1
@findex mbx_close/3
This primitive closes the mailbox specified, breaking all the links from
or to it.

@item mbx_link(@var{+MbxI}, @var{+MbxO})
@itemx mbx_link(@var{+MbxI}, @var{+RPass}, @var{+MbxO}, @var{+WPass}, @var{+TimeOut})
@findex mbx_link/2
@findex mbx_link/5
This links one mailbox (@var{MbxI}) to another (@var{MbxO}), allowing one to
one, many to one, one to many or many to many communication.
Linking a mailbox to itself gives an error.

@item mbx_unlink(@var{+MbxI}, @var{+MbxO})
@itemx mbx_unlink(@var{+MbxI}, @var{+RPass}, @var{+MbxO}, @var{+WPass}, @var{+TimeOut})
@findex mbx_unlink/2
@findex mbx_unlink/5
This breaks the link between @var{MbxI}  and @var{MbxO}.

@item mbx_getlinks(@var{+Mbx}, @var{-Links})
@itemx mbx_getlinks(@var{+Mbx}, @var{+TimeOut}, @var{+RPass} , @var{-Links})
@findex mbx_getlinks/2
@findex mbx_getlinks/4
Not implemented yet.  
This returns the links of the specified mailbox. @var{Links} is a list
with two elements, the first is a list with the addresses of mailboxes
to which @code{Mbx} is linked to, and the second element is a list with
the addresses of mailboxes linked to @var{Mbx}.
@end table

@node MbxIO, MbxMisc, MbxInit, MailboxPrimitives
@comment  node-name,  next,  previous,  up
@subsection Reading and Writing from Mailboxes

@table @code
@item mbx_send(@var{+Mbx}, @var{?Term})
@itemx mbx_send(@var{+Mbx}, @var{+Flag}, @var{+TimeOut}, @var{?Term}, @var{+WPass})
@findex mbx_send/2
@findex mbx_send/5
This sends a term to the mailbox specified by the global address @var{Mbx}.
Sending is asynchronous (and therefore buffering is provided).

@item mbx_recv(@var{+Mbx}, @var{-Term})
@itemx mbx_recv(@var{+Mbx}, @var{+Flag}, @var{+TimeOut}, @var{-Term}, @var{+RPwd?})
@findex mbx_recv/2
@findex mbx_recv/5
This reads a term from the mailbox specified by the global address
@var{Mbx}.  @var{Flag} specifies whether the message to be received is out
of band data or normal data. @var{TimeOut} specifies whether call is in
@code{block}, @code{poll} or timeout (@var{TimeOut} is a number in
seconds) mode. @code{block} means that the call will suspend until a
message is available. @code{poll} means that if there is no message
available, the call will fail with TIMEOUT error.  @var{TimeOut} means
that the call will suspend for a message for at most the time specified
and then, if there is no message available, it will fail.  @var{RPwd} is
an integer password for reading the mailbox.

@item mbx_look(@var{+Mbx}, @var{-Term})
@itemx mbx_look(@var{+Mbx}, @var{+Flag}, @var{+TimeOut}, @var{-Term}, @var{+RPass})
@findex mbx_look/2
@findex mbx_look/5
This reads a term from the mailbox @var{Mbx}.  It is a blocking primitive.
A @code{mbx_look} call does not remove the message read. The mailbox is
locked after such a call, so any other @code{mbx_read} or
@code{mbx_look} calls suspend until the mailbox is unlocked. The reading
process is supposed to test the message read and, depending on whether
it is suitable or not, it should call @code{mbx_commit} or
@code{mbx_discard}, both of which unlock the mailbox.  @code{mbx_commit}
or @code{mbx_discard} (whichever is chosen) should be run sequentially
after @code{mbx_look}, otherwise a SEQUENCE error will occur.

@item mbx_commit(@var{+Mbx})
@itemx mbx_commit(@var{+Mbx}, @var{+Flag}, @var{+TimeOut}, @var{+RPass})
@findex mbx_commit/1
@findex mbx_commit/4
This unlocks the mailbox @var{Mbx} removing the message read, so the next
reader will read a different message.

@item mbx_discard(@var{+Mbx})
@itemx mbx_discard(@var{+Mbx}, @var{+Flag}, @var{+TimeOut}, @var{+RPass})
@findex mbx_discard/1
@findex mbx_discard/4
This unlocks the mailbox @var{Mbx} without removing the message read, so
the next reader will read the same message.

@item mbx_check(@var{+Mbx})
@itemx mbx_check(@var{+Mbx}, @var{+Flag}, @var{+TimeOut}, @var{+RPass})
@findex mbx_check/1
@findex mbx_check/4
This primitive checks whether there is a message available in the
mailbox specified.  It is a non-blocking primitive.

@item mbx_clear(@var{+Mbx})
@itemx mbx_clear(@var{+Mbx}, @var{+Flag}, @var{+TimeOut}, @var{+Pass})
@findex mbx_clear/1
@findex mbx_clear/4
This removes all the normal data or out of band data kept in the specified 
mailbox.
@end table

@node MbxMisc,  , MbxIO, MailboxPrimitives
@comment  node-name,  next,  previous,  up
@subsection Miscellanious Mailbox Predicates

@table @code
@item mbx_bind(@var{+Mbx}, @var{+Atom})
@itemx mbx_bind(@var{+Mbx}, @var{+TimeOut}, @var{+Atom}, @var{+RPass})
@findex mbx_bind/2
@findex mbx_bind/4
This binds a global mailbox address to a global service in the mailbox
server, making the address accessible to the whole system. There can
be different services (@var{Atom}) with the same address (@var{Mbx}), but
not one service with different addresses.

@item mbx_getid(@var{+Atom}, @var{-Mbx})
@itemx mbx_getid(@var{+Atom}, @var{+TimeOut}, @var{-Mbx}, @var{+Pass})
@findex mbx_getid/2
@findex mbx_getid/4
This returns the global mailbox address associated with the global service 
specified. If the service is not recorded in the internal data base, the 
primitive fails.

@item mbx_getname(@var{+Mbx}, @var{-Atom})
@itemx mbx_getname(@var{+Mbx}, @var{+TimeOut}, @var{-Atom}, @var{+Pass})
@findex mbx_getname/2
@findex mbx_getname/4
This returns the global service associated with the global mailbox address
specified. If the address is not recorded in the internal data base, the
primitive fails.

@item mbx_initdb(@var{-Ptr})
@itemx mbx_initdb(@var{-Ptr}, @var{+TimeOut})
@findex mbx_initdb/1
@findex mbx_initdb/2
This initializes the internal data base reading pointer, allowing 
sequential access to it using the @code{mbx_getdb/4}  primitive. Returns an 
identifier for the initialize pointer.

@item mbx_getdb(@var{+Ptr}, @var{-Atom}, @var{-Mbx})
@itemx mbx_getdb(@var{+Ptr}, @var{+TimeOut}, @var{-Atom}, @var{-Mbx}, @var{+RPass})
@findex mbx_getdb/3
@findex mbx_getdb/5
This returns the global service and the global mailbox address associated
with it, reading sequentially from the internal data base. The next call
to this primitive will return the next data base entry. @var{Ptr} is the
identifier for the internal data base pointer.

@item mbx_closedb(@var{+Ptr})
@itemx mbx_closedb(@var{+Ptr}, @var{+TimeOut})
@findex mbx_closedb/1
@findex mbx_closedb/2
It closes the internal data base reading pointer created by 
@code{mbx_initdb/1}. 
@end table

The last two primitives always succeed, except when the arguments are 
incorrect. 

