%
% x-kernel v3.3
%
% Copyright (c) 1996,1993,1991,1990  Arizona Board of Regents
%

\section{Utility Routines}\label{util_lib}

\subsection{Storage}\label{storage}
\index{xMalloc}
\index{xFree}
\index{X\_NEW}

\subsubsection{xMalloc}

Essentially the same as the Unix malloc routine. Causes an {\xk} abort
if no storage is available; therefore, it has no error return value.
\medskip

{\var char *xMalloc(int size)}
\medskip

\noindent
The {\xk} provides a macro, {\em X\_NEW}, that can be used to allocate
space of a certain type.
\medskip

{\var \#define X\_NEW(type) (type *)xMalloc(sizeof(type))}

\subsubsection{xFree}

Frees previously allocated memory.
\medskip

{\var int xFree(char *buf)}

\subsection{Time}\label{time}

The {\xk} uses a time structure that is the same as that of Unix.

\var
\begin{tabbing}
xxxx \= xxxxxx \= xxxx \= \kill
\>typedef struct \{\\
\>\>long \>sec;\\
\>\>long \>usec;\\
\>\} XTime;\\
\end{tabbing}
\rm
\index{XTime}

\subsubsection{xGetTime}\label{xGetTime}
\index{xGetTime}

Sets {\var time} to the current time of day.
\medskip

{\var void xGetTime(XTime *time)}

\subsubsection{xAddTime}\label{xAddTime}
\index{xAddTime}

Sets {\var result} to the sum of {\var time\_1} and {\var time\_2}.
Assumes {\var time\_1} and {\var time\_2} are in standard time format
(i.e., does not check for integer overflow of the usec value).
\medskip

{\var void xAddTime(XTime *result, XTime time\_1, XTime time\_2)}

\subsubsection{xSubTime}\label{xSubTime}
\index{xSubTime}

Sets {\var result} to the difference of {\var time\_1} and 
{\var time\_2}.  The resulting value may be negative.
\medskip

{\var void xSubTime(XTime *result, XTime time\_1, XTime time\_2)}
\medskip

\subsection{Panic Conditions}

\subsubsection{xAssert}\label{xAssert}
\index{xAssert}

If the expression {\var exp} evaluates to FALSE, the {\xk} will print
a message and halt.
\medskip

{\var xAssert(bool exp)}
\medskip

Note that {\var xAssert} statements are macros which are only active
in DEBUG mode (see Section~\ref{config}).  In OPTIMIZE mode, {\var xAssert}
and trace statements go away completely.  You should keep this in mind
to avoid bugs that show up only in OPTIMIZE mode.  For example, the
statment:

\begin{verbatim}
      xAssert(mapResolve(map, key, &p) == XK_SUCCESS);
\end{verbatim}

\noindent
will have no effect in OPTIMIZE mode.  You should be careful to
separate the operation and the check of the return code, as follows.

\begin{verbatim}
      res = mapResolve(map, key, &p);
      xAssert(res == XK_SUCCESS);
\end{verbatim}

\subsubsection{xError}\label{xError}
\index{xError}

Non-fatal error conditions can print warnings even in nondebugging
mode by using the {\var xError} call.
\medskip

{\var xError(char *ErrorString)}

\subsection{Byte Order: ntohs, ntohl, htons, and htonl}\label{byte_order}
\index{ntohs}
\index{ntohl}
\index{htons}
\index{htonl}

The byte order functions are the same as the Unix functions.
\medskip

\var
\begin{tabbing}
xxxx \= xxxxxx \= \kill
\>u\_short \>ntohs(u\_short n)\\
\>u\_long  \>ntohl(u\_long n)\\
\>u\_short \>htons(u\_short n)\\
\>u\_long  \>htonl(u\_long n)\\
\end{tabbing}
\rm

\subsection{Checksum}\label{checksum}
\index{Checksum}

\subsubsection{inCkSum}\label{inCkSum}
\index{inCkSum}

Calculates a 16-bit 1's complement checksum over {\var buffer} (of
length {\var length}) and {\var message}, returning the bit complement
of the sum.  {\var length} should be even and the buffer must be
aligned on a 16-bit boundary.  {\var length} may be zero.
\medskip

{\var u\_short inCkSum(Msg *message, u\_short *buffer, int length)}

\subsubsection{ocsum}\label{ocsum}
\index{ocsum}

Returns the 1's complement sum of the {\var count} 16-bit words
pointed to by {\var hdr}, which must be aligned on a 16-bit boundary.
\medskip

{\var u\_short ocsum(u\_short *hdr, int count)}

\subsection{Strings to Hosts}\label{str_to_hosts}

Utility routines exist for converting from string representations of
IP and Ethernet addresses to their structural counterparts and
vice-versa.

\subsubsection{ipHostStr}\label{ipHostStr}
\index{ipHostStr}

Returns a pointer to a string with a ``dotted-decimal'' representation
of IP host {\var host} (e.g., ``192.12.69.1'').  This string is in a
static buffer, so it must be copied if its value is to be preserved.
\medskip

{\var char *ipHostStr(IPhost *host)}

\subsubsection{str2ipHost}\label{str2ipHost}
\index{str2ipHost}

Interprets {\var str} as a ``dotted-decimal'' representation of an IP
host and assigns the fields of {\var host} accordingly.  The operation
fails if {\var str} does not seem to be in dotted-decimal form.
\medskip

{\var XkReturn str2ipHost(IPhost *host, char *str)}

\subsubsection{ethHostStr}\label{ethHostStr}
\index{ethHostStr}

Returns a pointer to a string with a representation of Ethernet host
{\var host} (e.g., ``8:0:2b:ef:23:11'').  This string is in a static
buffer, so it must be copied if its value is to be preserved.
\medskip

{\var char *ethHostStr(ETHhost *host)}

\subsubsection{str2ethHost}\label{str2ethHost}
\index{str2ethHost}

Interprets {\var str} as a six-hex-digit-colon-separated
representation of an Ethernet host and assigns the fields of 
{\var host} accordingly.  The operation fails if {\var str} does 
not seem to be in the correct format.
\medskip

{\var XkReturn str2ethHost(ETHhost *host, char *str)}

\subsection{Host Name Service}\label{host_names}
\index{host names}
\index{dns rom option}

A simple way of mapping host name strings to host IP addresses is provided 
via rom file entries (see Section~\ref{rom_files}) and the interface 
function {\var xk\_gethostbyname}.

During {\xk} startup, rom file lines beginning with the string ``dns''
are parsed into name and address components and added to the host name
table.  E.g.:

\begin{verbatim}
        dns umbra 192.12.69.97
\end{verbatim}

The host name must be less than 64 characters in length.

\subsubsection{xk\_gethostbyname}\label{xk_gethostbyname}
\index{xkgethostbyname}

This function will look up a hostname and return its IP address in
{\var addr}.  The name must be an exact match to a rom file entry; no
substrings are allowed.  If the name is not found, the return code
indicates failure.
\medskip

{\var XkReturn xk\_gethostbyname(char *name, IPhost *addr)}

\subsection{ROM file parsing utilities}\label{ROM}
\index{rom file parsing}

When writing a protocol that provides user-configurable ROM file
options, you can make use of the ROM file parsing utilities to process
the ROM file entries.  To use these utilities:

\begin{enumerate}

\item{}
Write separate routines to handle each ROM option your protocol will
support.  These routines should be of the following type:

\var
\begin{tabbing}
xxx \= xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\= \kill
\>typedef XkReturn (*ProtlRomOptFunc)(Protl protl, char **fields,
int numFields,\\
\>\>int lineNumber, void *arg)
\end{tabbing}
\rm

The ROM file parsing code will call this handler routine when it finds
an appropriate line in the ROM file.  The number of fields on that
line and the fields themselves will be placed in {\var numFields} and
{\var fields}, respectively.  The line number is provided to allow the
handler to produce error messages if desired.

If the handler returns {\var XK\_FAILURE}, the parsing code will print
a generic ``ROM file format error'' message, specifying the name of
the protocol and the line number.

\item{}
Create an array of {\var ProtlRomOpt} structures which bind option
names to their handling functions.  There is one {\var ProtlRomOpt}
structure for each ROM option.

\var
\begin{tabbing}
xxx \= xxxxxx \= xxxxxxxxxxxxxxxxx \= xxxxxxxxxx \= \kill
\>typedef struct \{\\
\>\>char      \>*name;     \>/* name of the option as specified in ROM file */\\
\>\>int       \>minFields; \>/* minimum number of fields for this option */\\
\>\>ProtlRomOptFunc \>func; \>/* handler function */\\
\>\} ProtlRomOpt;
\end{tabbing}
\rm
\index{ProtlRomOpt}

\item{}
Somewhere in your protocol's initialization code, call 
{\var findProtlRomOpts}.
\index{findProtlRomOpts}

\var
\begin{tabbing}
xxx \= \kill
\>XkReturn findProtlRomOpts(Protl protocol, ProtlRomOpt *opts, int numOpts,
void *arg)
\end{tabbing}
\rm

This routine scans through the ROM file, looking for lines where the
first field matches either the protocol name or the full instance name
of {\var protocol} (e.g., if the protocol instance is 
{\var ethdrv/SE0}, ROM file entries with either {\var ethdrv/SE0} or 
{\var ethdrv} would match).  When such a match is found, the array 
{\var opts}, of {\var ProtlRomOpts}, is scanned.  If the second field 
of the line matches the name field of one of the {\var opts} entries, or if
the name field of one of the {\var opts} entries is the empty string,
the {\var ProtlRomOptFunc} for that option is called with the
protocol, all ROM fields on that line, the number of fields on that
line, the line number and the user-supplied argument.

If the first field of a ROM line appears to match {\var protocol}, but
none of the supplied {\var opts} entries matches the second field, an
error message will be printed and {\var XK\_FAILURE} will be returned.
The rest of the ROM entries will not be scanned.  This same behavior
results from the {\var ProtlRomOptFunc} returning {\var XK\_FAILURE}
and from a ROM line with too few fields for its associated handler.

\end{enumerate}

As an example, consider a protocol which supports two ROM options, a
{\var port} option and an {\var mtu} option, both of which take single
integer parameters.  The example in Figure~\ref{fig:romopt} shows how
this protocol would interface with the {\var romopt} parsing
utilities.

\begin{figure}
\caption{Interfacing with the {\var romopt} parsing utilities \label{fig:romopt}}
\begin{verbatim}
static XkReturn readMtu(Protl, char **, int, int, void *);
static XkReturn readPort(Protl, char **, int, int, void *);

static ProtlRomOpt opts[] = {
    { "mtu", 3, readMtu },
    { "port", 3, readPort }
};

static XkReturn
readMtu(Protl self, char **arr, int nFields, int line, void *arg)
{
    PState *ps = (PState *)self->state;

    return sscanf(arr[2], "%d", &ps->mtu) < 1 ? XK_FAILURE : XK_SUCCESS;
}

static XkReturn
readPort(Protl self, char **arr, int nFields, int line, void *arg)
{
    PState *ps = (PState *)self->state;

    return sscanf(arr[2], "%d", &ps->port) < 1 ? XK_FAILURE : XK_SUCCESS;
}

foo_init(Protl self)
{
    ...
    findProtlRomOpts(self, opts, sizeof(opts)/sizeof(ProtlRomOpt), 0);
    ...
}
\end{verbatim}
\end{figure}
