The FTS C Client Library Reference Manual.

This file document the FTS C client library interface. The Concepts chapter give some explications about the concepts underlying the communications with FTS; read that first if you don't have any familiarity with the FTS client/server architecture.

Other chapters give detailed informations about the programming API.


Introduction

The FTS C library is a set of C functions allowing an application to communicate with a FTS server, using some kind of bytestream oriented interface; the communication is implemented on a bytestream oriented protocol; while an application is free to interface directly to a server physically accessing the available physical connection (at least, in the cases where this connection is documented, like for sockets and pipes based connections), this library greately simplify the work by providing a higher level framework for handling the client/server interface. This library is written in C, and optimized for interfacing with C or C++ applications.

The idea of this library is to cope essentially with the syntax of the communication, and to avoid dealing with the semantic of the applications implemented with FTS; the basic idea is to provide a way to exchange information between FTS clients and servers, but to make as few assumption as possible on what these messages mean and on their purpose; in this way the library is completely generic, and can be used for any kind of applications.

The basic item of information exchanged between FTS clients and servers is called a message; a message is a command chosen in a predefined set of commands, with as arguments an ordered set of values of type chosen between a predefined set of types, sent to a target subsystem within the destination system (client or server).

The semantic of the command actually depends on the target subsystem; the library itself does not impose any semantic to the messages, but allows the application programmer to define subsystems with their specific semantic; the FTS server, together with the library, provides a number of predefined subsystems, like the Max interpreter, or other subsystem dealing with the configuration and so on; but these predefined subsystems are just installed on top of the library as the other, and future version of FTS will allow to configure which subsystem to install.

The library provides two asynchronous message streams, in the server to client and in the client to server directions.

The library defines also a generic event mechanism, as a client based subsystem, that allows the server to provide information on server's situation and state change without making assumption on the kind of application connected as a client.

The next chapters document the functions used to send and receive messages, and the way to create and access messages, and how to cope with events; in the appendix you will find the description of the bytestream protocol and the predefined subsystems together with their semantic.


The Server Interface

The library define an abstraction, the fts_server that represent the server and the connection to the server, in the application; this section document functions dealing with this abstraction.

Opening a Connection

fts_server *fts_open(int connection_type, char *name, char *options)

It creates a fts_server structure, and connect it to the server manager; the server structure is fully initialized; this function can be used to create connections on multiple servers, with the limit of one server for each connected machine. The connection_type argument specify how to connect to the FTS server; some values are strictly architecture dependent; currently implemented values are as following; other values can be implemented in future releases, or alternative versions of the library.

The name argument identify the server to connect to, when it is not completely specified by the connection type; the semantic of the name is actually connection_type dependent, and documented below. The options argument is a string coding a number of server and connection dependent options that are interpreted at the open time; see below for specific semantic.

The possible connection types are:

and are documented below.

Sink Connection

A Sink Connection is a fake connection, that throw away all the messages sent thru it; it is provided in order to simplify debugging of applications. The name and options arguments are not used in this case.

Pipe Connection

A pipe connection connects to the server thru a Unix pipe; the server will run on the same CPU as the client. The name and options arguments are not used in this case.

Pipe Connection

A pipe connection connects to the server thru a Unix named pipe; the server will run on the same CPU as the client; currently supported only in the DEC Alpha and SGI workstations. The name argument is used to generate two names for the input and output pipes (name.from and name.to). The options argument is not used in this case. Named pipes can be used in order to simplify debugging of user modules added to fts; running FTS directly from a debugger with the -n name option will connect FTS to the named pipe.

ISPW Connection

An ISPW connection connects to the server running in a ISPW card thru shared memory; supported only on the Next Cube, for NextStep 3.1 and 3.2 only. The name and options arguments are not used in this case.

Socket Connection

A socket connection connect to the server thru the FTS daemon, by means of an TCP connection; supported in all the environment with a UNIX like socket interface, and in some other environment supporting sockets, like MacOS with the right extensions. The name argument is the internet name or address of the machine where the daemon reside.

The options argument is interpreted as an unordered set of character; characters have the following meaning:

w
Write only client: the daemon will not send anything to this client.

b
Batch mode: the daemon will give priority to global bandwidth with respect to response time for this client; recomended for clients that may receive a lot of data from the server but don't need a fast round-trip time (i.e. they don't have graphic updates or so on ..).

a
Attached mode: quit the server when last client disconnect.

d
Detached mode: don't quit the server when the last client disconnect.

Closing a Connection

void fts_close(fts_server *server)

Close the connection represented by server; the actual server may be shutdown or not, depending on the connection and the running mode of the server and daemon, if any; it will be shutdown for all the connections type that allow only one client, anyway. Every reference to the structure pointed by server is illegal after calling fts_close on it.

Getting Infos About a Connection

fts_connection_status fts_get_connection_status(fts_server *server)

Return the status of the connection represented by server. The fts_connection_status is an enum with the following possible values and meanings:

not_connected
A manager has not yet been connected: this probabily means that an error (and its relative event) occurred during the connection setup.

output_connected
A manager has been connected in output, but the connection is not yet set up for input, so you cannot call fts_poll or the fts_get_fd functions; this probabily means that the server is not yet up and running, or that the connection is not completely set up, yet.

connected
A manager has been connected, and you can do input and output operation on the connection.

dead
The connection broke down: probably an error (and its relative event) occurred during the server normal operations.

int fts_have_input_fd(fts_server *server)

int fts_get_input_fd(fts_server *server)

Some kind of connection may use a file descriptor to connect to the server; in this case the file descriptor can be accessed in order to use the select function to decide when to poll the server; this usually avoid an active waiting loop and can spare the client CPU resources w.r.t. a poll loop without select.

The fts_have_input_fd function return a non-zero value if and only if the connection represented by server use a file descriptor; it can be called only if the connection with the server is fully established, i.e. if the fts_get_connection_status function return connected; programmers are formally discouraged from trying to infere the result of this function directly from the connection_type passed to the fts_open function; the same connection type may or not use a file descriptor depending on the version of the software, and the hardware and software platforms; this function is the only way to know if a file descriptor can be obtained.

The fts_get_input_fd function return the file descriptor that can be used in select; warning: any other use of this file descriptor is discouraged, and may bring to unknown results; in particular, the users should not assume that this file descriptor is the actual channel between the client and the server and that they can write and read unparsed messages directly to this file descriptor.

Sending a Message

void fts_send(fts_server *server, fts_mess *mess)

Send the mess message to server; the message must be created and filled with the message relative primitives, according to the message protocol defined in the appendix.

void fts_cacheing_on(fts_server *server)

void fts_cacheing_off(fts_server *server)

void fts_flush_cache(fts_server *server)

If cacheing is on, server cache all the messages in an internal buffer up to a certain dimension, and then send the message all together; it may reduce communication overhead on certain kind of connection when there are a lot of messages send, like during a patch loading.

fts_cacheing_on set on the cacheing, and fts_cacheing_off disable the cacheing; the fts_flush_cache forces the server to send all the messages that are stored in the internal cache. This feature may be removed in a future release.

Receiving Messages

void fts_poll(fts_server *server);

void fts_install_subsystem(char type, void (* fun)(fts_server *server, fts_mess *mess)

The input from a server is done by polling; in the case where server support a file descriptor, the programmer can use a select to avoid wasting cpu resources polling the server when there are no data ready; otherwise, the polling should be done regularly; anyway, the server to client connection is flow controlled, so that if the client don't poll the connection fast enough, the server will stop to generate events, without blocking the normal FTS computation.

The fts_poll function poll the connection represented by server; for all the correctly formatted messages received, fts_poll will call the corresponding subsystem function; as the protocol specify, the target subsystem is specified by the first character of the message; the subsystem function is installed at any time by the fts_install_subsystem function; the subsystem function will be called with as argument server, and the message parsed in a fts_mess structure and passed in the mess argument; the function should not free the message, and should copy all the arguments needed, because the message itself will be freed when the function return. Uncorrectly formatted messages, or messages for an uninstalled subsystem will be discarded, without any error signalling.


Messages

This group of function allows to create, access and manipulate messages, received or sent thru the server; the representation is unique for outgoing or ingoing messages.

A message is conceptually made of:

The client library is independent from the actual meaning of the messages; for a list of implemented target subsystem, and for the meaning of the commands and argument, see the documentation of the FTS protocol in appendix A.

Creating and Freeing a Message

The following functions are used to get or free a message structure:

fts_mess *fts_mess_new(void)

Create and return an empty message structure.

void fts_mess_free(fts_mess *mess)

Free the mess message structure after its use.

These two functions keep a free list of used messages and optimize memory allocation; so there is no need to store used messages in the application to spare a call to fts_mess_new and to fts_mess_free, that are very efficient. The only reason to keep a message is when you want to send it many times, unchanged or almost unchanged.

Filling a Message

The following functions are used to fill up a message; there are two kind of functions to add arguments to a message: the first type adds an argument at the end of the already existing arguments, the second set an argument in a specific position; if the second kind is used, the programmer should take care that there are no empty arguments in the middle of the message.

void fts_mess_set_req(fts_mess *mess, int req)

Set the request id; the request id is a reference to this message that the server may use in error messages and such, to identify the original message the error refer to. Setting the request id is optional; if not set, a convenctional value of minus one is used, meaning no request id specified.

void fts_mess_set_type(fts_mess *mess, int type)

Set the type of the message mess to type

void fts_mess_set_cmd(fts_mess *mess, int cmd)

Set the command field of the message mess to cmd.

void fts_mess_add_long(fts_mess *mess, long val)

Add a long argument of value val to the message mess.

void fts_mess_add_float(fts_mess *mess, float val)

Add a float argument of value val to the message mess.

void fts_mess_add_string(fts_mess *mess, char *val)

Add a string argument to the message mess; the val pointer is stored in the message structure, but the string itself is not copied in the message structure; it is the application responsability to not free or change the string until the message has been sent and freed.

void fts_mess_add_string_copy(fts_mess *mess, char *val)

Add a string argument to the message mess; the string val is copied in the message structure; the application is free to reuse the string when this function return. The malloc'ed memory will be freed when the message is freed.

void fts_mess_set_long(fts_mess *mess, long val, int pos)

Set the long value val as the argument in position pos of the message mess.

void fts_mess_set_float(fts_mess *mess, float val, int pos)

Set the float value val as the argument in position pos of the message mess.

void fts_mess_set_string(fts_mess *mess, char *val, int pos)

Set the string value val as the argument in position pos of the message mess. The pointer val is stored in the message structure, but the string itself is not copied in the message structure; the application should not free or change the string until the message has been sent and freed.

void fts_mess_set_string_copy(fts_mess *mess, char *val, int pos)

Set the string value val as the argument in position pos of the message mess. The string is copied in the message structure; the application is free to reuse the string when this function return. The malloc'ed memory will be freed when the message is freed.

void fts_mess_append(fts_mess *mess, fts_value_list *args)

Append the whole content of a value list as arguments to the message. Value list are structures that contain a list of tagged values and are documented below.

Getting Message Arguments

The following functions are used to access a message, and to get and check the types of arguments and so on.

int fts_mess_get_req(fts_mess *mess)

Get the request id stored in the message; a value of minus one means that no request id was specified. This function is actually implemented as a macro.

char fts_mess_get_type(fts_mess *mess)

Return the type of the message mess, i.e. the target subsystem. This function is actually implemented as a macro.

char fts_mess_get_cmd(fts_mess *mess)

Return the command of the message mess. This function is actually implemented as a macro.

int fts_mess_get_nargs(fts_mess *mess)

Return the number of arguments stored in the messages mess. This function is actually implemented as a macro.

fts_value_list *fts_mess_get_args(fts_mess *mess)

Get all the arguments of the message as a value list. This function is actually implemented as a macro.

int fts_mess_is_long_arg(fts_mess *mess, int i)

Return non zero if the argument i of mess is of type long. This function is actually implemented as a macro.

int fts_mess_is_float_arg(fts_mess *mess, int i)

Return non zero if the argument i of mess is of type float. This function is actually implemented as a macro.

int fts_mess_is_string_arg(fts_mess *mess, int i)

Return non zero if the argument i of mess is of type string, and the string itself have not been copied in the message structure. This function is actually implemented as a macro.

int fts_mess_is_string_copy_arg(fts_mess *mess, int i)

Return non zero if the argument i of mess is of type string, and the string itself have been copied in the message structure. This function is actually implemented as a macro.

int fts_mess_is_chars_arg(fts_mess *mess, int i)

Return non zero if the argument i of mess is of type string. This function is actually implemented as a macro.

long fts_mess_get_long_arg(fts_mess *mess, int i)

Return the argument i of mess, assuming that it is of type long; it is an error to apply this function if fts_mess_is_long_arg(mess, i) would return 0. This function is actually implemented as a macro.

float fts_mess_get_float_arg(fts_mess *mess, int i)

Return the argument i of mess, assuming that it is of type float; it is an error to apply this function if fts_mess_is_float_arg(mess, i) would return 0. This function is actually implemented as a macro.

char *fts_mess_get_string_arg(fts_mess *mess, int i)

Return the argument i of mess, assuming that it is of type string; it is an error to apply this function if fts_mess_is_chars_arg(mess, i) would return 0. This function is actually implemented as a macro.


Events

An event is the representation of a condition that may occur in the system; raising an event signal to the system that the represented condition actually occurred; the condition can be an error or abnormal condition, but can also be something that occur in the normal behaviour of the system; for example, the MAX subsystem objects signal a change of status to their graphic representation by means of an event.

An event can be raised in the FTS server, in the daemon (if used), in the client library or in the application itself; the client library transparently handles all this cases with a uniform mechanism; anyway, note that if the event is raised in the server, it is sent to the client by means of a message, so it will affect the client only the next time the fts_poll is called; while if the event is raised locally in the application, it is seen immediately.

When an event is raised other arguments may be specified to give more informations about the condition; an event is specified by a pair of integers, called event and tag; the semantic of the tag is event specific; can be used to specialize an event, but also for other purposes.

An handler is a function that is called by the FTS client library when an event is raised; at most one handler is invoked for an event; the association between events and handler to call is called event table; the client library maintain an event table for every fts_server structure instantiated, and one global event table; typically, handlers designed to handle global error conditions are put in the global table, while handlers designed to handle server dependent conditions are installed in the server table.

An handler can be installed for a particular event/tag pair, or for only an event value (and will be called regardless of the tag value), or for any event and any tag; if more than one handler are suitable for the same event, which handler will be called is implementation dependent; so the application should not make assumption on a particular selection criteria in these cases.

When an handler is installed, other two values can be stored in the event table, two void * pointers, one called owner and one called user_data; they are both passed to the handler when called; the only difference between the two is that handlers to be deinstalled can be chosen using the owner, and not the user_data value.

Installing and Deinstalling Event Handlers

The handler type is defined as follow:

typedef void (* fts_handler)(fts_server *server, long req, long event, long tag, fts_value_list *args, void *owner, void *user_data);

The event arguments are passed as fts_value_list; a set of functions and macros are provided to create and access this structure (see Value Lists)

void fts_add_handler(fts_server *server, long req, long event, long tag, fts_handler handler, void *owner, void *user_data)

Install the handler in the server event table, for the request id req, event event and tag tag, with the given owner and used_data values; if any value (tag, event, and request id) is zero, only the other values are used to match the event; if all the values are zero, all the events match.

void fts_remove_handlers(fts_server *server, long req, long event, long tag, fts_handler handler, void *owner)

All the handlers matching the arguments will be removed from the global event table; to match means either that the values are the same, or that the argument passed is 0, or NULL, depending of the type; for example, req, event and tag to zero, and handler to NULL, we can remove all the handlers that were installed for a given owner; while specifing event and leaving tag, handler and owner to zero (or NULL) we can remove all the handlers for a particular event.

Raising Events

void fts_raise_event(fts_server *server, long req, long event, long tag, fts_value_list *args)

Raise a event defined by the req and event/tag pair, with the given arguments; the arguments are specified as an value list (see Value Lists).

Synchronous Events

void fts_wait_for(fts_server *server, long req, long event, long tag, fts_handler handler, void *owner, void *user_data)

Poll the server until an event, specified by the req and the pair event/tag, is raised; when the event is raised, the specified handler will be invoked, with the event arguments and the owner and user_data specified.

The event we wait for can be raised remotely in the server, or locally as a side effect of the response to some other message.

Note that currently the fts_wait_for implementation don't use the server file descriptor if available, so it uses more CPU resources than needed; this will be fixed in some future release.

Value Lists

Event argument are represented by the fts_value_list C type; fts_value_list is a type defining variable list of type tagged value; these values are used in events, and internally to represent message arguments; element type supported are float, long, char * (copied or shared); the copied and shared string type tag identify both a char *; by convention they are used for new copied strings that may/should be freed after the use, and for pointers to shared/static strings that should not be copied.

The following documents a number of macros to deal with fts_value values; they are documented as functions.

Operation On Lists

fts_value_list *fts_value_list_new(void)

Create and return a new, empty value list; the value list module handle a free list of value lists, so freeing and reallocating a value list is usually better and faster than reusing old an existing one.

int fts_value_list_get_size(fts_value_list *list)

Return the number of element in list.

fts_value_list *fts_value_list_copy(fts_value_list *list)

Copy the list, generating a new value list.

void fts_value_list_append(fts_value_list *list, fts_value_list *append)

Append the elements contained in the list append in the list list.

fts_value_list *fts_value_list_sublist(fts_value_list *old, int start, int end)

Generate a new list, containing a sublist of the list old, from the element start, to the element end. The list is a read only list, cannot be modified with the set and add family of functions; it can be copied, if modifications are needed.

fts_value_list *fts_value_list_sublist_copy(fts_value_list *old, int start, int end)

Generate a new list, containing a sublist of the list old, from the element start, to the element end. The list is a newly allocated list, and can be modified.

void fts_value_list_free(fts_value_list *list)

The list list is freed; no further references should be done on the list.

Setting an element in a list

void fts_value_list_add_long(fts_value_list *list, long val)

Add at the end of list a value of type long, value val.

void fts_value_list_add_float(fts_value_list *list, float val)

Add at the end of list a value of type float, value val.

void fts_value_list_add_string(fts_value_list *list, const char *val)

Add at the end of list a value of type string, value val.

void fts_value_list_add_string_copy(fts_value_list *list, const char *val)

Add at the end of list a value of type string, value val; the value is copied in a private allocated memory.

void fts_value_list_set_long(fts_value_list *list, long val, int pos)

Set the element of list in position pos to type long, value val.

void fts_value_list_set_float(fts_value_list *list, float val, int pos)

Set the element of list in position pos to type float, value val.

void fts_value_list_set_string(fts_value_list *list, const char *val, int pos)

Set the element of list in position pos to type string, value val.

void fts_value_list_set_string_copy(fts_value_list *list, const char *val, int pos)

Set the element of list in position pos to type string, value val; the value is copied in a private allocated memory.

Accessing an element in a list

long fts_value_list_get_long(fts_value_list *list, int pos)

Return the long value of the element of list in position pos; it is an error getting a long value of a non long element.

float fts_value_list_get_float(fts_value_list *list, int pos)

Return the float value of the element of list in position pos; it is an error getting a float value of a non float element.

char fts_value_list_get_string(fts_value_list *list, int pos)

Return the string value of the element of list in position pos; it is an error getting a string value of a non string element.

Checking an element in a list

int fts_value_list_is_long(fts_value_list *list, int pos)

Return non zero if the value of the element of list in position pos is of type long.

int fts_value_list_is_float(fts_value_list *list, int pos)

Return non zero if the value of the element of list in position pos is of type float.

int fts_value_list_is_chars(fts_value_list *list, int pos)

Return non zero if the value of the element of list in position pos is of type string (either a private copy or not).

int fts_value_list_is_string(fts_value_list *list, int pos)

Return non zero if the value of the element of list in position pos is of type string, and is not a private copy.

int fts_value_list_is_string_copy(fts_value_list *list, int pos)

Return non zero if the value of the element of list in position pos is of type string, and is a private copy.


Include Files

The FTS C API is defined by the include file ftsapi.h, that define prototypes for all the functions documented in this manual, and for all the constants mentioned.

Protocol constants are defined in the file protocol.h.

Predefined events and event tags are defined in the file evdefs.h.


The Bytestream Protocol

The FTS client and the server communicate by means of messages; a message is a data abstraction, including a message type, a message command, and a number of arguments.

The communication is implemented by means of a secure bidirectional bytestream media, as a TCP connection; this appendix documents the way messages are sent thru the bytestream; it do not document the message semantic, which is partially documented in the next appendixs.

Note that the bytestream protocol is considered documented in the strict sense: it is correct to implement applications that don't use the C client library and access directly to the byte streams, under the condition that comply with this protocol and with the session protocol recomendations; this allow the writing of other client library, for example in other programming languages.

The protocol do not include any kind of error correction; the basic protocol don't include either any kind of flow control; the flow control, when needed, is implemented by means of special messages, and so is not part of the basic protocol definition.

The current version of the protocol send all the data using ASCII characters. The communication is partially human readable.

Future version of the protocol may include a more compact binary version; anyway, it is guaranteed that in all the future version of the protocol:

The protocol is completely asynchronus: i.e. the two directions of the communication are completely independent at this level of abstraction; the representation used for message in both direction is the same.

Constants used here are defined in the protocol.h file.

A message is represented by a ASCII string generated by the following grammar:

<message> ::=  <type> <cmd> <arg-list> <end-of-message>

<type> ::= <ASCII-char>
<cmd>  ::= <ASCII-char>

<arg-list> ::= <empty-string> | <arg> <arg-list>
<arg> ::= <int-arg> | <obj-arg> | <float-arg> | <string-arg>
<int-arg> ::= <pos-int-arg> | <neg-int-arg>
<pos-int-arg>   ::= <pos-int-type-tag> <hex-unsigned-int-representation>
<neg-int-arg>   ::= <neg-int-type-tag> <hex-unsigned-int-representation>
<obj-arg>   ::= <obj-type-tag> <hex-unsigned-int-representation>
<float-arg> ::= <float-type-tag> <float-representation>

<string-arg> ::= <start-string-tag> <string-body> <stop-string-tag>
Where:

<ASCII-char>
is any ASCII character.
<empty-string>
is the empty string.
<pos-int-type-tag>
is LONG_POS_CODE ('i').
<neg-int-type-tag>
is LONG_NEG_CODE ('n').
<obj-type-tag>
is OBJ_CODE ('o').
<float-type-tag>
is FLOAT_CODE ('z').
<start-string-tag>
is STRING_START_CODE '\"'
<stop-string-tag>
is STRING_END_CODE '\"'
<end-of-message>
is EOM_CODE '\n' (the hex value 0d).

Since messages cannot contain a new-line character in their body, a new-line character can be put in the string as the string ``\n'' (two characters); a double quote can be put in a message content as the string ``\"'' (two characters); the client library, and the FTS message support automatically performs these quoting/dequoting operations when needed.

Since the type tag performs as a token separator in the grammar, the obvious choice of 'f' as type tag for the floating point values would not work, because it would introduce an ambiguity at the end of a int value, sent as hexadecimal.

Longs are sent with a sign-value representation, to avoid introducing dependencies from the word machine size in the protocol; the sign is included in the type tag, so there are two type tag for long, positive long and negative long.

The floats are sent in printf/scanf style representation.

The maximum values for scalar arguments is not specified by the protocol itself, and depend on the connected subsystem.

Arguments are positionals, i.e. first argument in the string is argument 0, second argument in the string is argument 1 and so on.

Messages can include any number tab and blanks; however, unless they occur inside a string, they are considered as lexical token separators.

This grammar do not handle the request ID; actually, the request ID is not a special field of the message, but it is always, for all the subsystems, the first argument of the message; this is left implicit in the documentation of the subsystem.


The Subsystems

This appendix document all the defined subsystem for the communication protocol.

The Void Subsystem

The void subsystem is identified by a target subsystem identifier equal to VOID_CODE (currently 'v'). Any message, in both directions, sent to the void subsystem is simply discarded; it can be used for debugging.

The Max Subsystem

The Max subsystem is identified by a target subsystem identifier equal to MAX_CODE (currently 'm'). The Max subsystem correspond to the Max interpreter; messages to this subsystem allow the creation and execution of a Max patch.

Commands, with their relative argument syntax and command semantics are defined as follows:

NEW_OBJ_CODE, long proc, long obj, string class, args ...

Create a new Max object; the object is created in processor number proc; processor are numbered from 0 up to the number of installed processors; if the FTS server is monoprocessor, the proc argument should be zero.

The object is given the identifier obj; it is an error to assign the same identifier to multiple objects; for a multiprocessor server, the identifier space is global to all the processors.

The class argument is the name of the class of the object. All the other args are passed to the class specific new function, so their semantic is class relative.

FREE_OBJ_CODE long obj

Free the object of identifier obj; the object will be immediately destroyed, and the resources used will be returned to FTS.

CONNECT_CODE long obj1, long outlet, long obj2, long inlet

Connect the outlet outlet of obj1 to the inlet inlet of obj2.

DISCONNECT_CODE long obj1, long outlet, long obj2, long inlet

Disconnect the outlet outlet of obj1 from the inlet inlet of obj2.

MESSAGE_CODE long target-obj, string message, long inlet, args ...
MESSAGE_CODE string target-name, string message, long inlet, args ...

Send the Max message message to an object, on the given inlet; the object can be specified either by its object identifier, or by a name; the ability to be identified by name is class specific; currently, only receive objects can be specified by name, but other classes can be built with this ability.

The arguments are passed to the object as they are; object identifier are converted in pointers to the objects themselves.

The Max Subsystem

The Meta Max subsystem is used to get information about objects and object classes, like how many inlets or which kind of message an object accept. The Meta Protocol is not (yet) documented.

The Manager Subsystem

The Manager subsystem is the subsystem that takes care of booting the server and of the pre-boot configuration (also of some post-boot configuration paramenters); the actual location of the subsystem depends on the configuration and on the type of connection used; for example, for coprocessor based server the manager is the part of the program that boot the coprocessor, so it must reside on the target machine; in case of a socket connection the manager is remote, while in case of a local connection the manager is local; in order to give a complete transparency to the user application, the communication with the manager is always performed with messages, regardless to the location of the manager; the library will route the messages as needed depending on the configuration.

At the moment, most of the manager messages are server specific; so we document here a manager protocol for each kind of server the library can directly bootstrap; in future releases the manager protocol will evolve in a server independent core, with a few server specific extensions.

The ISPW Manager

The ISPW manager subsystem is charged with all the pre-boot configuration of the ISPW FTS server, and with the bootstrap itself; so many of the supported messages are, at least in the current version, ISPW dependent.

setftsdir

Set the ftsdir; the directory is interpreted locally from the manager.

setsysdir

Set the sysdir, i.e. the directory where some ISPW system file are kept; the directory is interpreted locally from the manager.

setthrottle

Set the three throttles; if the server is running change them dynamically.

setadvances ...

Set the advances values; if the server is running change them dynamically. The values should be more than one, less or equal to the number of processors. Advances should be set after the nproc configuration value.

setcpuslots ...

Set the cpus slot; should be set before the server startup. The values should be equal to the number of processors. This message should be sent after the nproc configuration value.

setmachversion

Set the mach version; should be set before the server startup. Note that in case of non local manager, the manager is free to ignore this message and to use informations locally available on the host.

setnproc

Set the number of processors used; should be set before the server startup.

setnboard

Set the number of ISPW boards installed in the machine; the other pertinent parameters are derived from this one.

opensdserver

Take the directory were to find the sound server executable, the sound server number, and the three throttle values to pass on to the server. Start the sound server with the given identifier.

closesdserver

Close (shutdown) the sound server with given identifier.

start

Boot/start the FTS server, with the previously set up configuration. Send this if the server status is server_down.

shutdown

Shutdown the server.

The Unix Manager

The Unix manager is used for Unix servers, usually connected to the daemon or the client thru a Unix pipe; the Unix manager handles server booting and shutdown, essentially.

setftsdir

Set the ftsdir; the directory is interpreted locally from the manager.

start

Boot/start the FTS server, with the previously set up configuration. Send this if the server status is server_down.

shutdown

Shutdown the server.

restart

Shutdown the server (if not already dead/down) and reboot it; used for cleanup; Send this is the server status is server_dead.

The Session Manager Subsystem

The Session Manager subsystem is the subsystem that handle a peer-to-peer connection, i.e. the connection between the client and the daemon, or between the client and the server, or between the daemon and the server; its purpose is to handle the connection itself, and not the message content. It provides two messages to initialize and quit the connection, and three message to handle flow control in the server to client direction.

This messages are usually sent and handled directly by the library; anyway, if a client write directly to the bytestream, it should at least send the first two.

INIT_CONNECTION
It is the first message sent to a freshly opened connection; its arguments are the argument of the fts_open function, i.e. server type (an int), name (a string) plus an optional options (a string) if specified; the semantic of the arguments is anyway connection specific but the purpose is to specify parameters that belong to the connection itself. This message may change in future releases.

QUIT_CONNECTION
It is the last message sent to a connection; it informs the other peer that the connection is going to be closed, and the other peer should take any action that this imply. It take no argument.

FLOW_CONTROL_ON
It is sent in the client to server direction, on a portion of the connection, to require flow control to be activated in this connection portion in the server-server direction; i.e. is used by a client, or daemon, to ask the daemon or server to use flow control in sending data to the client; flow control is not activated if not explicitly requested; the argument is the flow control window size. The library may use flow control or not depending on the connection type; also the window size is connection type dependent.

FLOW_CONTROL_OFF
Disable flow control in a flow controlled session.

ACK_MESSAGE
It must be sent by the client to declare reception of one or more messages from the server; the server (or daemon) will send a number of message equal to the flow control window size without waiting for ack messages, and then will stop; the client resume the communication by sending an ack_message with an int argument declaring how many messages has been received and processed since the last ack message. It is the application responsability to decide how many ack message to send (i.e. if to acknowledge every single message or if to acknowledge group of messages with a single acknowledgement message); the library use an heuristic based on the size of window.

The Event Subsystem

The Event subsystem is the subprotocol used to send events to the clients; the format of the messages is unique, and include a VOID_COMMAND command field, the event and the tag coded as the first two integer argument of the message, and the event arguments coded as the other message arguments.

The Daemon Control Subsystem

The daemon control subsystem is a subsystem that is actually installed in the daemon itself, and whose purpose is to perform control operations on the daemon itself; the functionalities offered by this message are currently available by means of the ftsc program (see the relative documentation), but can easily incorporated in any user application.

The defined messages are as following.

DEBUG_LEVEL
Set the debug level of the daemon, i.e. the amount of information that the daemon display in its debugging printout, that can be the system log or the standard error (see the ftsd documentation). The argument values are int that can go from 0 (completely quiet) to 4; debug level 1 correspond to the normal logging of new clients to the system administration files; level 4 give an extremely detailed log of the daemon activities.

RESET_DAEMON
Resets the daemon completely: drops the server and all the clients, clean up all the internal data structures.

HALT_DAEMON
Shutdown the daemon.

ATTACH_MODE
If the argument is nonzero set the attach mode of the daemon (see the ftsd documentation), otherwise set the detach mode.

GET_VERSION
Ask the daemon to send a DAEMON_VERSION event with information about itself.


Predefined Events And Tags

The client library define a number of events and the related tags; the numbers below 1024 are reserved for events and tags handled by the library, and cannot be used by the application; FTS itself and the FTS subsystems define a number of events; refer to the FTS documentation for details.

Note that events and tags int, while represented in the client library with the local int type, should have values that can be represented with a 32 bit int.

Tag meaning is event specific; this means that tags are not identified by globally unique numbers, but only unique only w.r.t. events.

Predefined Events are:

FATAL_ERROR
The fatal error event, raised only when something prevent the continuation of the program itself, like end of memory, or an inconsistency in the program data structure.

CONNECTION_ERROR
The connection error event: it suggest that something wrong is going on in the connection with the server.

PROGRAM_ERROR
The program error event: it means that a request operation is not compatible with the known status of the server/manager or with the programming limits; the program can continue, but something went wrong. It probably indicate a programming error.

SERVICE_REQUEST
Services request: the server ask the client for some kind of service or action; the application may/should implement the corresponding handlers.

CLIENT_INFO
Client info events: it is raised to give informations about the client/library activities to the application itself.

SERVER_INFO
Server Info events: it is raised to give informations about the server activities to the application; they may requested by the application, or raised spontaneously; they are raised either by the server itself, or by the manager.

FIRST_APPLICATION_EV
The first event available for user programming; refer to the FTS documentation for information on the event number allocation policy.

The predefined tags for each event are documented in the following.

Tags for FATAL_ERROR

Tags defined for the FATAL_ERROR event.

EXHAUSTED_MEMORY
Specify an out of memory error.

Tags for CONNECTION_ERROR

Tags defined for the CONNECTION_ERROR event.

CONNECTION_DIED
The connection with the server is not active any more; it is probabily a problem related to the connection itself, like a network problem.

SERVER_DIED
A problem occurred in the server, and the server itself is not active any more.

UNKNOWN_SERVER_MESSAGE_CMD
The server received a message for an implemented subsystem with an unknown command field.

BAD_FTSD_ADDR
An invalid, unknown, or anyhow wrong Internet address has been specified as the FTSD daemon address.

UNKNOWN_TCP_SERVICE
The FTSD service is not known in the target machine; almost surely a configuration/installation problem.

CANNOT_CREATE_SOCKET
The client couldn't open the socket to communicate with the server.

CANNOT_CONNECT
The client was not able to set up the connection at the fts_open time.

CONNECTION_CLOSED
The connection was explicitly closed by the other peer, daemon or server.

Tags for PROGRAM_ERROR

Tags defined for the PROGRAM_ERROR event.

MESSAGE_TOO_LONG
A message exceeding the maximum allowed length was sent.

INVALID_TH1_VALUE
On the ISPW manager, the throttle 1 was set out of range, and defaulted to 1.

INVALID_TH2_VALUE
On the ISPW manager, the throttle 2 was set out of range, and defaulted to 0.

INVALID_TH3_VALUE
On the ISPW manager, the throttle 3 was set out of range, and defaulted to 0.

INVALID_ADVANCE
On the ISPW manager, the advance was set out of range, and defaulted to a proper (undocumented) value.

INVALID_MNGR_MESSAGE
The manager received an invalid message.

UNKNOWN_MNGR_MESSAGE
The manager received an unknown message.

SOUNDDISK_ERROR
The ISPW manager was not able to start the sound server.

Tags for SERVICE_REQUEST

Tags defined for the SERVICE_REQUEST event.

PRINT_REQUEST
The server request to show to the user the argument string. Currently this event is used for the Max post function, and most of the time there is an error event; in future releases, the use of this event will be greately reduced, and substituted with specific events carrying more information relative to the actual situation.

Tags for CLIENT_INFO

No tags are currently defined for the CLIENT_INFO event.

Tags for SERVER_INFO

Tags defined for the SERVER_INFO event.

No user visible tags are currently defined for the CLIENT_INFO event.


The FTS C Client Library Reference Manual.

Authors : Maurizio De Cecco, François Déchelle

Copyright © 1995 IRCAM.