Subject: Re: Attribute API

From: James Kempf <[email-masked]>
Date: Tue, 27 Jun 2000 22:39:57 -0700

Part of the point of the C API was to keep it close to the protocol
to make it easier to implement. In fact, the way we managed to implement
an SLP UA in 10K of Java bytecodes was to duplicate the C API in Java.
So adding anything is likely to remove the attraction for small clients.

Additionally, I'm not in general a big fan
of complex APIs in C because of C's primitive memory management.
If a client wants complex data structures, they should use a generalized data
structure library, take the hit and program the data structure themselves,
or use a language with decent memory management semantics, like Java.
If a complex API is desired, a language that has marginally more
support for better memory management like C++ comes to mind as a possible
alternative (and there are public domain runtime systems that provide
excellent memory management for C++).

But if people think something like this is needed, we can look
into adding it to 2614 as we go to draft standard, or issuing
a companion RFC that contains a more complex C API built on top
of the more primitive one. I can say for
a fact, however, that it will be difficult to impossible to
get Sun to implement this or any other major change in the
SLP API. Minor tweaks like improving multithreading for 
SLPGet/SetProperty() are doable, but any major changes
will probably not happen unless there is some major customer
demand.

			jak
>
>Here's a first try at the attribute API. This suggestion includes as much
>reasonable/useful functionality as I could think of, and may require some
>reduction. 
>
>Some possible reductions:
> Reducing SLPAttrGet_*() to SLPAttrGet(), and losing all template-based
>type checking. 
> Ditto for SLPAttrSet().
> Dropping the "lazy" parameter to SLPAttrSet*() and forcing all copies to
>be made on the function call. 
>
>
>Here it is (Note, this does not include iterators). 
>
>---CUT HERE---
>
>Proposed SLP Attribute API
>
>Data Structures:
>
>The Attribute API requires three data-structures: a container to hold the 
>attributes, an iterator to loop over the attributes, and a type enumberation. 
>The container is:
>
>typedef void *SLPAttributes;
>
>The SLPAttributes type is either returned (as the result of an attributes 
>request), or explicitly allocated (during attribute registration). It serves
>as a handle to an arbitrary number of attributes, which can be added to,
>iterated over, or submitteed to the SA/DA. Even though it is possible to
>associate an instance of SLPAttributes with a template, only the values that
>are explicitly set by the application will be sent to the SA/DA on update. 
>The type is opaque.
>
>
>The iterator is:
>
>typedef void *SLPAttrIterator;
>
>The SLPAttrIterator is explicitly allocated to iterate over an instance of the
>SLPAttributes type. It is an opaque type.
>
>
>The type enumeration is:
>
>typedef enum {
>	SLP_BOOLEAN = 1,
>	SLP_INTEGER = 2,
>	SLP_KEYWORD = 3, 
>	SLP_STRING = 4,
>	SLP_OPAQUE = 5
>} SLPType;
>
>Each value corresponds to a type specified in RFC 2609.
>
>
>
>Creation/Destruction:
>
>
>#include <slp.h>
>#include <stdio.h>
>
>SLPError SLPAttrAlloc(
>		const char *lang, 
>		const FILE *template_h,
>		const SLPBoolean strict, 
>		SLPAttributes *slp_attr
>)
>
> Description:
>
> SLPAttrAlloc() creates and initializes a new instance of SLPAttributes. 
>
>
> Parameters:
>
>  lang
>
>  A pointer to a NULL terminated array of characters containing the RFC 1766
>  Language Tag for the natural language locale of requests and registrations
>  issued on the handle.  Pass in NULL or the empty string, "" to use the local
>  the machine is configured to use.  
>
>
>  template_h
>
>  An open filehandle to the template that these attributes are to conform to. 
>  May be NULL if type checking is not desired. The API will leave the file
>  handle open, but pointing to the eof.
>
>
>  strict
>
>  A boolean flag specifying how strict the API should be when verifying tag
>  names against the template specified by template_h. If this field is
>SLP_TRUE,
>  then any attempt to register an invalid tag name/type will fail, and
>  SLP_TYPE_ERROR will be returned. If this field is SLP_FALSE, the registration
>  of invalid tag names will succeed, but a SLP_TAG_WARNING message will be 
>  returned. 
>
>  If template_h is NULL, the value of strict must be ignored.
>
>
>  slp_attr
>
>  A pointer to an SLPAttributes handle, through which the instance is
>  returned. 
>
> Returns:
>
>  SLP_OK
>   If the SLPAttributes were instantiated properly. 
>  SLP_LANGUAGE_NOT_SUPPORTED
>   If the lang specified is not supported. This will occur if the template
>   specified in the template_h is not of the requested language. Note:
>   Allocation and initialization must not occur. The application may request
>   again with the template_h field set to NULL.  
>  SLP_PARSE_ERROR
>   If the template is not of the required format. As with
>   SLP_LANGUAGE_NOT_SUPPORTED, allocation does not occur. 
>  SLP_MEMORY_ALLOC_FAILED
>   If the API ran out of memory.
>  SLP_INTERNAL_SYSTEM_ERROR
>   An unspecified error occured.
>  SLP_NOT_IMPLEMENTED
>   If the function is not implemented.
>
>
>SLPError SLPAttrFree(
>		SLPAttributes attr_h
>)
>
> Description:
>
> Deallocates all resources held by the specified instance of SLPAttributes. 
>
> Parameters:
>  attr_h
>
>  The attribute handle specifying the attributes to be deallocated. 
>
> Returns:
>  SLP_OK
>   If the SLPAttributes were deallocated properly.
>  SLP_INTERNAL_SYSTEM_ERROR
>   An unspecified error occured.
> 
>
>
>#include <slp.h>
>
>SLPError SLPAttrIteratorAlloc(
>		SLPAttributes attr_h,
>		SLPAttrIterator *iterator,
>)
>
> Description:
>
>  Creates and initializes an iterator for use with a set of attributes. 
> 
>
> Parameters:
>
>  attr_h
>
>  Handle to the attributes to iterate over. 
>
>
>  iterator
>
>  The new iterator is allocated and returned through this field. 
> 
>
> Returns:
>
>  SLP_OK
>   If instantiation occured properly.
>  SLP_MEMORY_ALLOC_FAILED
>   If the API ran out of memory. 
>  SLP_PARAMETER_BAD
>   If the value of attr_h is NULL.
>  SLP_NOT_IMPLEMENTED
>   If the function is not implemented.
>  
>
>Attribute Manipulation:
>
>The attribute manipulation functions are made available by type. There are
>five "sets", and five "gets", each corresponding to one of the five types SLP
>is aware of. Each takes a value from the application and performs all
>necessary operations to allow the SLPReg() function to send it across the
>network. 
>
>The only 
>
>
>#include <slp.h>
>
>SLPError SLPAttrSet_bool(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		SLPBoolean val
>)
>
> Description:
>
>  Sets the value of the named boolean attribute to that of the passed value. 
>  If the value of the named attribute has already been set, it is reset. 
> 
>
> Parameters:
>
>  attr_h
>
>  Attribute handle to set in.
>
>
>  attribute_tag
>
>  The name of the attribute to set. Must be a NULL terminated string.
>
>
>  val
>
>  The value to set the variable to. 
>
> 
> Returns:
>
>  SLP_OK
>   If the value of attribute_tag is valid (according to the template), and
>   value of attr_h is not NULL.
>  SLP_TAG_WARNING
>   If the attribute_tag is not in the template the attr_h was initialized
>   with, and the strict flag is clear (SLP_FALSE), this warning will be 
>   returned. 
>   Note: the value IS set. 
>  SLP_TAG_ERROR
>   If the attribute_tag is not in the template attr_h was initialized with,
>   and the strict flag is set (SLP_TRUE), this error is returned. 
>   Note: the value is NOT set. 
>  SLP_TYPE_ERROR
>   Returned if a variable with the attribute_tag exists in the template, but 
>   has a different type. The strict value has no effect on this return value. 
>   Note: The value is NOT set. 
>  SLP_MEMORY_ALLOC_FAILED
>   If an internal allocation failed. 
>  SLP_PARAMETER_BAD
>   If the passed value is neither SLP_TRUE nor SLP_FALSE.
>  SLP_INTERNAL_SYSTEM_ERROR
>   Some misc. error. 
>  SLP_NOT_IMPLEMENTED
>   If the function is not implemented.
>
>
>
>#include <slp.h>
>
>SLPError SLPAttrSet_int(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		const int val
>)
>
> Description:
>
>  Sets the value of an integer variable. 
> 
>
> Parameters:
>  See SLPAttrSet_bool(). 
>
> 
> Returns:
>  See SLPAttrSet_bool(). 
> 
>
>
>#include <slp.h>
>
>SLPError SLPAttrSet_str(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		const char *val
>)
>
> Description:
>
>  Sets the value of a string variable. Note that the passed string is copied
>  by the API.
> 
>
> Parameters:
>  See SLPAttrSet_bool(). 
>
>  val
>
>  val must be NULL terminated. It does not need to be explicitly escaped. 
>
> 
> Returns:
>  See SLPAttrSet_bool(). 
> 
>
>
>#include <slp.h>
>
>SLPError SLPAttrSet_keyw(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		const char *val,
>		const SLPBoolean lazy
>)
>
> Description:
>
>  Sets the value of a keyword variable.  
>
> Parameters:
>  See SLPAttrSet_bool(). 
>
>  lazy
>
>  If the lazy variable is set (SLP_TRUE), the API will not copy the string
>  contents until the SLPRegAttr() function is called. This saves unnecessary
>  copies, but it does oblidge the application to keep the passed string
>  available until SLPRegAttr() is called. 
>  
>  If the lazy variable is clear (SLP_FALSE), the API immediately copies the
>  string; allowing the application to immediately dispose of the passed value.  
>
>
> Returns:
>  See SLPAttrSet_bool(). 
>  SLP_TYPE_ERROR
>   If the value passed contains characters outside the range of *** to ***.
>
>
>#include <slp.h>
>
>SLPError SLPAttrSet_str(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		const char *val,
>		const SLPBoolean lazy
>)
>
> See SLPAttrSet_keyw(). 
> 
>
>
>#include <slp.h>
>
>SLPError SLPAttrSet_opaque(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		const char *val,
>		const unsigned int len,
>		const SLPBoolean lazy
>)
>
> Description:
>
>  Sets the value of an opaque attribute.  
>
> Parameters:
>  See SLPAttrSet_keyw().
>
>
>  len
>
>  The length of the opaque data field, in bytes. This allows NULL characters
>  to be embedded in the string. 
>
>
>  lazy
>
>  See SLPAttrSet_keyw().
>  
> 
> Returns:
>  See SLPAttrSet_bool(). 
>
>
>
>
>#include <slp.h>
>
>SLPError SLPAttrGet_bool(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		SLPBoolean *val
>)
>
>SLPError SLPAttrGet_int(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		int *val
>)
>
> Description:
>
>  Gets the value of an attribute. 
>
> Parameters:
>  attr_h
>
>  Attribute handle to get from. 
>
>
>  attribute_tag
>
>  The name of the attribute as a NULL terminated string. 
>
>  
>  val
>
>  A pointer through which the attribute value can be returned.
>
> 
> Returns:
>  SLP_OK
>   If the value is set properly. 
>  SLP_TAG_ERROR
>   If the attribute_tag is unknown. 
>  SLP_TYPE_ERROR
>   If the attribute could not be converted into the requested type. See the
>   end of this section for a description of when this occurs.     
>  SLP_MEMORY_ALLOC_FAILED
>   If an internal allocation failed. 
>  SLP_INTERNAL_SYSTEM_ERROR
>   Some misc. error. 
>  SLP_NOT_IMPLEMENTED
>   If the function is not implemented.
>
>
>
>#include <slp.h>
>
>SLPError SLPAttrGet_str(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		char **val
>		int *len
>)
>
>SLPError SLPAttrGet_keyw(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		char **val
>		int *len
>)
>
>SLPError SLPAttrGet_opaque(
>		SLPAttributes attr_h,
>		const char *attribute_tag,
>		const char **val,
>		unsigned int *len
>)
>
> Description:
>
>  Gets the value of an attribute. 
>
> Parameters:
>  attr_h
>
>  Attribute handle to get from. 
>
>
>  attribute_tag
>
>  The name of the attribute as a NULL terminated string. 
>
>  
>  val
>
>  A pointer through which the attribute value can be returned. The returned
>  value must be collected with SLPFree(). 
>
>
>  len
>
>  A pointer through which the length of val can be returned. For 
>  SLPAttrGet_keyw() and SLPAttrGet_str() the returned value MAY be -1, which
>  indicates that the length of the string must be determined by the
>  application. For SLPAttrGet_opaque() this value MUST be set by the API.
>
> 
> Returns:
>  SLP_OK
>   If the value is set properly. 
>  SLP_TAG_ERROR
>   If the attribute_tag is unknown. 
>  SLP_TYPE_ERROR
>   If the attribute could not be converted into the requested type. See the
>   end of this section for a description of when this occurs.     
>  SLP_MEMORY_ALLOC_FAILED
>   If an internal allocation failed. 
>  SLP_INTERNAL_SYSTEM_ERROR
>   Some misc. error. 
>  SLP_NOT_IMPLEMENTED
>   If the function is not implemented.
>
>
>
>Note that an SLP_TYPE_ERROR will occur during a "get" when:
> SLPAttrGet_bool() is used to get an attribute whose value is anything other
>    than a boolean.
> SLPAttrGet_int() is used to get an attribute whose value is neither an
>    integer nor a boolean.
> SLPAttrGet_keyw() or SLPAttrGet_str() is used to get an opaque value (one
>	that contains an unescaped character outside of the range *** to ***). 
>
>Note that SLPAttrGet_opaque() can be used to get any value. 
>
>
>Submitting to DA/SA:
>
>#include <slp.h> 
>
>SLPError SLPRegAttr( 
>	SLPHandle slp_h, 
>	const char* srvurl, 
>	unsigned short lifetime, 
>	const char* srvtype, 
>	const SLPAttributes *attr_h, 
>	SLPBoolean fresh, 
>	SLPRegReport callback, 
>	void* cookie 
>) 
>
>
>Same as the old version. Note that the old version (with explicit control over
>the setting of the attribute string) should still exist. 
>
>
>
>Finding the Type of an Attribute:
>
>
>#include <slp.h>
>
>SLPError SLPAttrType(
>    SLPAttributes attr_h,
>	const char *attribute_tag,
>	SLPType *slp_type
>)
>
>
> Description:
>
>  Queries the type of the requested attribute. 
> 
>
> Parameters:
>
>  attr_h
>
>  A handle to the attribute structue to query.
>
>
>  attribute_tag
>
>  The name of the attribute to query.
>
>
>  slp_type
>
>  A pointer to the type field to set. 
>
> 
> Returns:
>  SLP_OK
>   If the attribute was queried and set. 
>  SLP_TAG_ERROR
>   The specified tag does not exist in attr_h.
>  SLP_INTERNAL_SYSTEM_ERROR
>   Any misc. error. 
>  SLP_MEMORY_ALLOC_FAILED
>   If a malloc failed. If this value is returned, the request failed. 
>  SLP_NOT_IMPLEMENTED
>   If the function is not implemented.
>  
>

---

From: Evan Hughes <[email-masked]>
Date: Wed, 28 Jun 2000 11:13:39 -0400 (EDT)

On Tue, 27 Jun 2000, James Kempf wrote:
...
> will probably not happen unless there is some major customer

  Alright. I was thinking of this in terms of the OpenSLP api: I'd like
more services to be made SLP-aware, and I think the easiest way to do this
is to make the SLPification process as easy as possible. On the client
side, this is no problem (the API is very sufficient in that area), but on
the SA side the API is a bit weaker:

  The attribute marshelling functionality will always be repeated, the SA
must _always_ take internal data, convert it to strings, escape it, copy
it into a bigger string, and then pass that string into the API. This is
basically drudge work that will always have to be done by an SLP service,
so it makes sense to farm it out to the API. Not only is it drudge work,
but it's inefficient (three mallocs, three string copies, one string
length, and one string parse) and error prone.

  Since we're looking at this in terms of an open source project, we want
to make SLP as usable/implementable as possible[*]. Ideally, making a
service SLP aware should be one day process. In its current state, the
attribute management will take up to a week. 

  I guess our goal is SLP advocacy (in the name of the greater good: IP
mobility and pervasive (calm) computing). We would like as many services
to be SLPified as possible. IMHO, the API's weak attribute manipulation is
a barrier to gaining acceptence from the wider community.

e

--
* - As I mentioned, we want to use SLP for resource discovery in wireless
networks. SLP fits our needs well, but there are no SLP-aware services, so
we need to make SLP-aware services. Since we don't have time to SLPify all
services, we want other people to SLPify their own services.

---

From: Terry Lambert <[email-masked]>
Date: Wed, 28 Jun 2000 13:44:11 -0700

Evan Hughes wrote:
>   Alright. I was thinking of this in terms of the OpenSLP
> api: I'd like more services to be made SLP-aware, and I
> think the easiest way to do this is to make the SLPification
> process as easy as possible. On the client side, this is no
> problem (the API is very sufficient in that area), but on

I ran into this problem in both the UA and the SA, not just
the SA.

I implemented an SA for the Cyrus IMAP4 and POP3 services,
and for Sendmail 8.9.3 (based on the access_db and providing
an SMTP relay for a client), along with service definitions
for these things that encoded various required things in the
URL, as well as a "where is my default HTTP server?" service
for Apache that understood workgroups and username as part
of the service request URL.

I had to implement the attribute stuff each time.  It was
complicated, and integrated poorly with each of them; I
have to say I like the proposed attribute API; it seems a
minimal requirement for quickly SLP-enabling _both_ SAs
_and_ UAs.

On the client side, I hacked up Mozilla for the HTTP, and
Pine for the POP3/IMAP4/SMTP services; I started with Pine
because "mozilla mail/news" wasn't there at the time.

I found that, at least for C UAs, it makes sense to have
these routines available in every case I attempted.

The printer SAs seem different, in that they tend to run
from static configuration data, making the reference
implementation useful.  For other services, where users
can come and go, so configuration data must be parsed as
part of the request, the relationship with the server is
much more intimate.  Likewise the relationship between a
UA asking for an SMTP relay for user "terry" in the
workgroup "engineering", and the mail client on whose
behalf the request is made.

So my personal opinion is that they are useful, but could
be better recast as a Vector containing attribute/value
pairs for the Java fanatics (i.e. the C version specifies
the iteration mechanism on an Opaque object, but the Java
version uses a Vector and a standard Vector Iterator,
instead).

---

Erik made the argument that memory management in C is not
very good.

This has some implications for the API.  The first thing it
implies is something that I've complained about before: the
API specified deallocation function.

It took me a while to understand how C could be implemented
the way the RFC specifies,; when I finally figured it out,
it was an obvious (in restrospect) ugly hack.  It works by
allocating the structure and all string data hung off it as
an oversized, monolithic allocation, and then setting the
pointers in the structure to point after the structure itself,
into the remainder of the allocation.

I think this abuses the C allocation functions to the point
that it's an implementation problem, and I'd suggest that
either an API specific free function be applied, so that a
hidden preamble containing a type code could be added by
overallocating and adjusting the pointer, so API allocated
objects could, instead, be freed recursively by examining
the type code, OR the allocations and deallocations should
all be explicit.  In other words, the current design assumes
garbage collection or a hack to get around making the free
an explicit part of the API.

-

The second thing it implies is that the argument in favor
of simplifying the pattern matching in order to decrease
memory footprint is doubly specious.  It's not only a bad
idea from the standpoint that there is another was to solve
the problem that doesn't require a huge footprint (see the
UNIX symlink/namei() reference in a previous post), but that
it's being violated in principle in any case, by the
assumption that the C API will allocate all its storage for
data references by the structure, instead of pointing to
static references.

> The attribute marshelling functionality will always be
> repeated, the SA must _always_ take internal data, convert
> it to strings, escape it, copy it into a bigger string, and
> then pass that string into the API. This is basically drudge
> work that will always have to be done by an SLP service, so
> it makes sense to farm it out to the API. Not only is it
> drudge work, but it's inefficient (three mallocs, three
> string copies, one string length, and one string parse) and
> error prone.

The UA also has this problem, if the UA is implemented in a
high level language, and is a legacy application being retrofit.

I think that it's as important to consider legacy clients, as
it is to consider legacy servers.

> I guess our goal is SLP advocacy (in the name of the greater
> good: IP mobility and pervasive (calm) computing). We would
> like as many services to be SLPified as possible. IMHO, the
> API's weak attribute manipulation is a barrier to gaining
> acceptence from the wider community.

Heh.  I just have to comment: OpenSLP will never ship as
part of AIX because of the license.  The Sun Reference
Implementation has a similar license problem that precludes
the IBM lawyers from approving it for shipping on AIX as
well, since the license grant is not in perpetuity.  That's
one of the reasons I was working on yet-another reference
implementations myself: I needed it for my own use.

In any case, I see attribute manipulation as being useful to
the general API, and if it can be frozen, I will implement
it locally, as well, so that will make two of us.

Note:	My stuff is on my own time with my own equipment,
	and has been since the new employment agreements
	came down the pike following the IBM acquisition, so
	it's not going to be under an equally commercial
	unfriendly license (somehow nobler for being IBM
	friendly); if I can only find the time to get it
	cleaned up and out the door, it will be a 2 clause
	UCB license, since I can't make people hold me
	harmless when putting it in the public domain.

-- Terry Lambert
-- Whistle Communications, Inc., an I.B.M. Company
-- [email-masked]
-------------------------------------------------------------------
This is formal notice under California Assembly Bill 1629, enacted
9/26/98 that any UCE sent to my email address will be billed $50
per incident to the legally allowed maximum of $25,000.