ARDP Library Interface Description
Below we provide a description of the interfaces to the ARDP library.
The ARDP v1 API (which is implemented and distributed as ARDP Release
1.0) is a superset of the ARDP v0 API.
This page's documentation covers the ARDP Version 0
facilities in the Prospero 5.3 release. Programmers using ARDP
release 1.0 or Prospero release 5.4 will also want to read ARDP - API
(Version 1).
Functions in the library that are not described here should be
considered internal and should not be called by the application.
In the functions that follow, more documentaton can be found in the
header preceding the function in the source code.
ARDP Errors
Many functions are listed as returning an ardp_errcode. In
the Prospero 5.3 release, this is actually an int; the
type was changed to ardp_errcode, a typedef for enum
ardp_errcode, in later releases. These errors, taken from
ardp.h, are as follows. The numeric values should not be relied
upon; use the symbolic names instead:
/* ARDP library error status codes. */
/* These must remain in the range 0-20 for compatibility with the Prospero
File System. */
/* Note that ARDP_SUCCESS must remain 0, due to code implementation. */
enum ardp_errcode {
ARDP_SUCCESS = 0, /* Successful completion of call */
ARDP_PORT_UNKN = 1, /* UDP port unknown */
ARDP_UDP_CANT = 2, /* Can't open local UDP port */
ARDP_BAD_HOSTNAME = 3, /* Can't resolve hostname */
ARDP_NOT_SENT = 4, /* Attempt to send message failed */
ARDP_SELECT_FAILED = 5, /* Select failed */
ARDP_BAD_RECV = 6, /* Recvfrom failed */
ARDP_BAD_VERSION = 7, /* bad version # in rdgram protocol */
ARDP_BAD_REQ = 8, /* Inconsistent request structure */
ARDP_TIMEOUT = 9, /* Timed out - retry count exceeded */
ARDP_REFUSED = 10, /* Connection refused by server */
ARDP_FAILURE = 11, /* Unspecified ARDP failure */
ARDP_TOOLONG = 12, /* Buffer too long for packet */
ARDP_TIMER_FAILED = 13, /* A call to gettimeofday() failed.
(this is ARI's addition; I'm not
sure that it's needed --swa) */
ARDP_CRITICAL_CONTEXT_NOT_SUPPORTED = 14, /* for ardp-v1 contexts */
ARDP_CRITICAL_SERVICE_FAILED = 15,
ARDP_CONTEXT_FAILURE = 16, /* more general than the CONTEXT ones above;
more specific than ARDP_FAILURE (or
ARDP_REFUSED, in some situations) */
};
typedef enum ardp_errcode ardp_errcode;
ARDP client functions
The following functions are exported by the ARDP library for use by
the client side of a connection:
- void ardp_abort(RREQ req) :
Aborts the specified request, sending an
abort message to the server if currently
active. If req is null,ardp_abort
will send aborts to servers for all active requests.
- ardp_abort_on_int(void) :
Sets interrupt handler to abort any
pending requests.
- int ardp_priority: Default priority for outgoing ARDP requests. Default is 0.
The default priority can be overridden for a particular connection by setting the priority member of the associated RREQ structure.
- ardp_process_active() :
Processes new responses to active requests.
If making an asynchronous request (i.e. if the ttwait passed to
ardp_send()
does not equal ARDP_WAIT_TILL_TO), then this
function must be called periodically, either
automatically within ardp_retrieve, explicitly,
or initiated by an interrupt when
a response becomes available on the UDP port.
This functions is also used on the server side. Normally a
server does not call it directly, since it is automatically called
by the ardp_retrieve*() family of functions
- int ardp_retrieve(RREQ req,int ttwait) :
Poll for, or wait ttwait microseconds for the
pending request req to complete. If ttwait is
-1, ardp_retrieve() blocks.
req is normally a pointer to an outstanding
ARDP request. ardp_retrieve() returns an error code. The
successfully completed request req is removed from
the ardp_completeQ.
Earlier versions of this documentation claimed that NOREQ
is not acceptable as an argument to ardp_retrieve(). In
fact, passing NOREQ is a query about whether any requests
have completed (successfully or unsuccessfully). We return
ARDP_SUCCESS if a complete request is available. (However, unlike in
the case where req is a specific request, we do not remove it
from the completeQ.)
ardp_retriev() will perform appropriate retransmissions for
all items on the ardp_activeQ if any timeouts occur
during the ttwait period. (This was not the
case before February 1997).
Returns ARDP_BAD_REQ if called on an RREQ that is not
on the activeQ or the completeQ.
If no request is ready when the timeout expires, returns
ARDP_PENDING.
- RREQ ardp_retrieve_nxt_nonblocking(void):
Like calling ardp_retrieve(), but not specifying any request,
and with no wait for a message.
Returns NOREQ or any completed message, if one is there.
- ardp_send(req,dname,dest,ttwait) :
Sends the request req to the host with domain name
dname or socket address dest, and waits
ttwait microseconds for a response.
ttwait may also be the constant
ARDP_WAIT_TILL_TO (or -1); this means that
ardp_send() should wait until the ARDP protocol's
timeout happens. Passing ttwait as 0 means
ardp_retrieve() is not called and
ardp_send() returns immediately.
- ardp_set_retry(to,rt) :
Set retry initial time out (to to seconds).
Specify that you want rt retries. Calling
this function is identical to the sequence of code:
ardp_config.default_timeout = to;
ardp_config.default_retry = rt;
ARDP server functions
The following functions and variables are exported by the ARDP library for use by
the server side of a connection:
- ardp_accept() :
Accepts new requests and places on appropriate
queues for subsequent processing. This must be called
periodically, either explicitly, or initiated by an interrupt
when a request becomes available on the UDP port.
ardp_accept() does not block. It does not call ardp_process_active(); keep this in mind if you are writing a program that acts as a client and as a server.
- ardp_bind_port(const char *portname) :
portname is the service name (in /etc/services) or number (a string in the format
"#decimal-port-number") of a port to be opened, on which the
server will listen for requests.
- RREQ ardp_get_nxt(void) :
Returns the next request to be processed.
If none available, it will block until one is received. Calls
ardp_accept().
ardp_get_nxt() does not call ardp_process_active(). It is not recommended that you use it if you are writing a program that acts as a client and as a server and there might be any outstanding (asynchronous) client requests.
- RREQ ardp_get_nxt_nonblocking(void) :
Returns the next request to be processed.
If none available, it will return the constant
NOREQ. Calls ardp_accept().
Does not call ardp_process_active()
- int ardp_redirect(RREQ req, struct sockaddr_in *target) :
Sends a redirect to the client indicating the the request
req should be sent to a new target server
identified in the second argument. For now, redirections
should only occur before any request packets have been
acknowledged, or response packets sent.
- ardp_respond(RREQ req, int opt) :
Used by a server to send the current response
packet once filled in. It will add the packet
to the transmission queue, and send it. To
indicate completion of a response, the
ARDP_RESP_COMPLETE option should be specified.
If the ARDP_RESP_NOSEND option is specified,
the packet will be added to the transmission queue
but not sent.
- ardp_refuse(RREQ req) :
Causes the request specified by req to be refused and
notification sent to the client.
- ardp_reply(RREQ req, int flags, const char *message) :
Queues message (appending it to the req structure)
and possibly sends it and other queued data to the
client. Will call ardp_respond() if any
completed packets can be sent (i.e., sends a
partial response to speed up client/server
interaction). Message is a null-terminated buffer.
Can't use this interface to send binary data
that might contain nulls; see
ardp_breply() below.
- int ardp_breply(RREQ req, int flags, const char
*message, int len):
Send a reply to a request; the reply might contain binary
data.
ardp_breply takes a request to which a reply
is to be sent,
a flags field, the contents of the reply message,
and a length count for the message.
ardp_breply() then adds
the response to the output queue for the request.
A length count of 0 indicates that the buffer is null-terminated.
(implementation note: by passing the 0 down to ardp_add2req, we
allow there to be only one pass through the buffer instead of 2.)
If the ARDP_REPL_COMPLETE flag has been specified, all data is sent.
Otherwise,
the response is buffered pending
subsequent calls to ardp_breply().
ardp_breply() immediately sends any full packets in
the buffered response.
The lower level function (ardp_respond) assigns packet numbers and
tags outgoing packets if necessary for a multi packet response.
ardp_reply()
calls ardp_breply() internally.
- ardp_rwait(RREQ req, int timetowait, int qpos, int stime) :
This function is called by a server to specify
a server requested time to wait for a response.
This value is returned to the client which
will treat it as an acknowledgment and will
defer subsequent timeouts and retries until
waiting timetowait seconds. Non-zero values
of qpos and stime will cause the current
the specified queue position and expected
system time to be provided to the client in
the same message.
- ardp_set_queuing_policy(int(*pf)(RREQ r1, r2),override) :
Sets a function used to determine queue
ordering on the server.
- ardp_set_prvport(int fd) :
Sets a file descriptor that has already been
opened as the privileged input port on which the server
will listen for requests.
- int ardp_acknowledge(req) :
Sends an acknowledgment message to the client indicating that
the server received a complete multi-packet request from the
client.
- char * (*ardp_vlog)(int type, RREQ req, const char *format, va_list ap) If you are writing a server and want the ARDP library to log information, you need to set this function-valued variable to some logging function. Its initial value is NULL.
type is a logging message type specified in
gl_log_msgtypes.h. req is the request which triggered this call to the logging function; it may be NOREQ. format is a format string acceptable to the stdio library printf() function (or the gostlib qsprintf() function). ap refers to the arguments to printf().
- void (*ardp_newly_received_additional)(RREQ nreq):
This function-valued variable may be set if you wish additional processing to be performed (e.g., prioritization) on a complete ARDP request that the server has just received. Its default value is NULL.
ARDP client and server interfaces
The following functions are exported by the ARDP library for use
by either the client and the server sides of a connection:
- RREQ ardp_get_nxt_all(enum ardp_gna_rettype *rettype) :
This function is intended to be used by programs which are
acting both as ARDP clients and as ARDP servers.
It acts as a combination of
ardp_get_nxt() and
ardp_retrieve(). If it returned a response
(acted as ardp_retrieve()),
*rettype will be set to
ARDP_CLIENT_PORT. If it returned a new
request for the server, *rettype will be set
to ARDP_SERVER_PORT.
If nothing available, it will block until one is received.
It blocks without calling ardp_process_active() appropriately. No retransmissions occur until just before it returns. If you don't want this to happen, then call ardp_get_nxt_all_timeout() with
a ttwait argument of ARDP_WAIT_TILL_TO
- RREQ ardp_get_nxt_all_timeout(enum ardp_gna_rettype *rettype,
int ttwait, int priority)
Acts as ardp_get_nxt_all(), with extensions:
ttwait specifies a timeout interval in
microseconds. -1 (ARDP_WAIT_TILL_TO) means wait forever. The client should set
priority to one of the two
distinguished values ARDP_CLIENT_PORT or
ARDP_SERVER_PORT. This indicates whether
ardp_get_nxt_all_timeout() will first check the client port
for replies or the server port for new requests.
It calls ardp_process_active() appropriately.
- void ardp_initialize(void) :
This function must be called before using the ARDP library.
It initializes ardp_config, the structure where the ARDP library looks for its
configuration information. If you aren't using the pconfig
routines in gostlib, you should still call ardp_initialize(), to keep
ardp_config from being full of junk.
ardp_initialize() also initializes the ARDP library's MUTEXES; these
are important for multi-threaded programs.
ardp_initialize() should not be called more than once during
the program's execution. (There is some code around that does call it
more than once, or calls p_initialize() in Prospero more than
once. This was never correct, although it usually works. It will
break multi-threaded code.)
ardp_initialize() should be called after you have
read in any command-line arguments with
p_command_line_preparse(&argc, argv) (q.v.). If you haven't
called this, then an error may be signalled. If you call
p_command_line_preparse() too late, then an error may be
signalled. If you call ardp_initialize(), or a function that
calls it, more than once, then an error may be signalled.
(The more robust thing to do would be to make it accept being
called multiple times, and we plan to add that functionality when convenient.).
- ardp_add2req(RREQ req, int flags, const char *buf, int len) :
Adds arbitrary data (including text) to a request which will
subsequently
be sent to the peer, and returns.
- RREQ ardp_rqalloc(void) :
Allocate a new request structure. If the user set an auxiliary
allocating-function with ardp_rqappalloc(),
ardp_rqalloc() will set the new request's
app.ptr member to the return value from invoking that
function.
- void ardp_rqappalloc(void * (* appallocfunc)(void)): see ardp_rqalloc().
- ardp_rqfree(RREQ req) :
Free a request structure. If the user set an auxiliary
freeing-function with ardp_rqappfree(),
ardp_rqfree() will invoke that function with
req's app.ptr function as its argument.
- void ardp_rqappfree(void (* appfreefunc)(void
*)): see ardp_rqfree().
- void ardp_rreq_to_in(RREQ rreq, INPUT in,
ardp_rreq_to_in_aux_INPUT in_aux):
Lets you feed RREQ structures to the gl_parse family of
functions in gostlib.
The following functions and variables are used internally by the ARDP
library; we are mentioning them so that users of ARDP will not be
confused by finding them in the ARDP source code and for the
convenience of those wishing to do further ARDP development. Some of
them may also be useful to applications writers in special
circumstances.
- ardp_headers()
: called by ardp_process_active() and ardp_send() before (re)transmitting packets.
- ardp_hostname2addr(const char *hostname, struct sockaddr_in *hostaddr): called by ardp_send(). This
function serves as a thread-safe version of gethostbyname();
gethostbyname() is not a re-entrant function since it uses
static data. ardp_hostname2addr() also caches
DNS values for efficiency. It will cache up to DNSCACHE_MAX (constant defined in ardp.h) entries.
- ardp_errcode ardp_hostname2name_addr(const
char *hostname_arg, char **official_hnameGSP, struct
sockaddr_in *hostaddr_arg):
Called by ardp_hostname2addr(). Thread-safe. Returns the
host's address in hostaddr_arg, and the official hostname in
official_hnameGSP. hostaddr_arg and
official_hnameGSP may be NULL pointers.
It is defined and reasonable to call ardp_hostname2name_addr() with
both arguments NULL; this causes a lookup to be made and entered
into the cache.
We usually cache the official hostname as well. This will also
cache numeric addresses, which can be useful.
The hostname_arg may in one of the three forms:
- 1) "hostname"
- 2) "hostname:port-no"
- 3) "hostname(port-no)"
If port-no is not specified (in the first form above), then
ardp_hostname2name_addr() will return with
hostaddr_arg->sin_port set to zero. If port-no is
specified, then hostaddr_arg->sin_port will be set to the
decimal integer value of port-no.
This function ignores ardp_config.default_port and
ardp_config.default_peer; those are examined at higher levels.
- ardp_errcode ardp_init(void): Called by
ardp_send() to bind the port on which the
client listens for replies.
ardp_init() may be called more than once. The semantics
are that on each subsequent call the old client port will be
closed and a new one opened and bound.
ardp_init() tries first to bind a privileged port. It tries
up to ardp_config.num_privp ports, starting at
ardp_config.first_privp, before giving up and
binding a non-privileged port.
ardp_init() binds the port's address to the
hosts's IP address; if there is more than one IP interface on
the host, then the interface associated with the primary
hostname is used. This means that all packets coming from the
host (even if they would normally be tagged with the address
of an alternate IP interface) will nevertheless be tagged with
the host's primary IP address. Presumably, therefore, the
responses might be sent by an inefficient route back to the
'primary address' rather than to the appropriate IP address as
would normally be automatically selected by client's internal
routing table.
The bound port's IP Address and UDP port number are stored in
the global variable:
struct sockaddr_in ardp_client_address_port.
This variable
is all zeroes until ardp_init() sets it.
The file descriptor of the newly bound port is in the global variable:
int ardp_port
ardp_init() returns:
- ARDP_UDP_CANT if one of the
socket system calls failed. In this case,
ardp_client_address_port will also be
set to all zeroes and ardp_port will
retain its value of -1 (meaning
uninitialized).
- ARDP_SUCCESS on successful completion.
Multi-threading:
This function is currently not written to be thread-safe.
Indeed, it would be difficult to design a thread-safe
version of it capable of being repeatedly called.
- ardp_rqlfree(RREQ req_list) :
Free a list of request structures.
- PTEXT ardp_ptalloc(void) :
Allocate a new packet structure.
- ardp_ptfree(PTEXT pkt) :
Free a packet structure.
- ardp_ptlfree(PTEXT pkt_list) :
Free a list of packet structures.
- ardp_showbuf(): Used by ardp_retriev() and
ardp_send() to display the packets received
and sent, when the pfs_debug flag is set appropriately.
- ardp_snd_pkt(PTEXT tpkt, RREQ nreq): used
internally on server side to send status/control packets.
- int ardp_xmit(RREQ req, int window):
Transmits up to window unacknowledged packets to the
peer. Called on the client side by ardp_send() and
ardp_process_active(); on the server side by
ardp_process_active().
- ardp__log(int type, RREQ req, const char * format, ...):
Logging function used by server-side functions to report
errors and status. This function only does something if
ardp_vlog has been assigned a value.
ARDP's configurable parameters are defined in a global data structure named
ardp_config. This structure is initially filled in by
ardp_initialize(), which uses the
p_config routines of gostlib. After your program
calls ardp_initialize(), you may set these members
directly.
You will normally not bother setting most of these parameters; skip
this section if you are just learning to use ARDP.
The members of ardp_config are:
- char *default_peer:
Name (in /etc/services) of the port
ardp_send() will use by default, unless one is
explicitly given. Overridden if default_port is set.
- int default_port:
Number of the port ardp_send() will use by default.
Overrides default_peer.
- int default_timeout:
Number of seconds before trying to retransmit a request.
To override this for a particular connection, set the timeout
member of the associated RREQ structure.
- int default_retry:
Number of times to retry a request (client).
To override this for a particular connection, set the retries
member of the associated RREQ structure.
- int default_window_sz: Peer window size
ardp will use for its default flow-control strategy. This is the
window size we assume our peer will accept in the absence of an
explicit request. Default value is 16 packets.
To override this for a particular connection, set the pwindow_sz
member of the associated RREQ structure.
- int max_window_sz:
The largest window size we will ever use, no matter what the peer
tells us. By default this is 256 packets.
- int first_privp:
(Client only): First privileged local port to try to send from; an
ARDP client uses this when it is running as root. This facility can
be used to provide security similar to that of the Berkeley "r"
commands.
- int num_privp:
(Client only) Number of privileged ports to try before giving up and letting the operating system assign us a nonprivileged port.
Additional ARDP interfaces (left out of the docs. before 8/14/97)
- u_int32_t myaddress(void): This
returns a 32-bit integer which is the 32-bit IP (Internet Protocol)
address of the host this function is called on.
- const char * myhostname(void):
The host name of the host this function is called on.
- const char *unixerrstr(void):
This is the printed string associated with the error code in the C
library's errno (variable) facility.
- int ardp_debug: This variable is zero by
default. Setting to values up to twelve (12) means that the ARDP
library will print additional diagnostic and progress information on
the stderr output stream. The most convenient value to set
it to is often nine (9); at values of 9 or greater, it will cause
the text of all packets sent back and forth.
- RREQ ardp_partialQ, ardp_pendingQ, ardp_runQ, ardp_doneQ:
These queues are used on the ARDP server. Very few users will ever
want to examine them, and they should more properly be considered
internal. When an ARDP server has received some packets of a
request, but does not have a complete request yet, an RREQ structure
with some fields still blank is on the
ardp_partialQ. When the last packet needed to
complete a request is received, the server moves the request to
ardp_pendingQ. When the request begins processing (when
it is returned from one of the ardp_get_nxt family of
functions), then it is moved to ardp_runQ. When the
server program is done processing, it indicates that it has completed
processing the request by giving it as an argument to one of:
- ardp_respond() with the ARDP_RESP_COMPLETE
option,
- ardp_refuse(),
- ardp_redirect()),
then the request is moved to the ardp_doneQ.
The queues are also discussed in the ARDP FAQ
- RREQ ardp_activeQ, ardp_completeQ: These
queues are used on the ARDP client. Once a message has been sent, its
RREQ is put on the ardp_activeQ. Either when the message has
timed out, or when a complete reply has been received by the client,
then ardp_process_active() puts the message's RREQ onto
the ardp_completeQ. RREQs are removed from the
ardp_completeQ by ardp_retrieve(),
ardp_retrieve_nxt_nonblocking(), and the
ardp_get_nxt_all functions that include the functionality
of ardp_retrieve().
The queues are also discussed in the ARDP FAQ
Authors:
Steven Augart <swa@ISI.EDU>,
Katia Obraczka <katia@ISI.EDU>.
File updated: August 18, 1997, Steven
Augart <swa@ISI.EDU>.