RFC 2614

An API for Service Location

๐Ÿ“… published June 1999, from ietf

An API for Service Location ๐ŸŽ€

okay bestie, this RFC is the spec for an API for Service Location (SLP), and it's giving main character energy ๐Ÿ’…โœจ. It was published in June 1999 under the Informational category ๐ŸŒธ, which means it shares info with the Internet community but doesn't set a standard. The authors are J. Kempf and E. Guttman from Sun Microsystems ๐Ÿงš. Its header doesn't list any document it obsoletes or updates ๐Ÿ™ˆ. The RFC number is 2614 and it's part of the Network Working Group stream ๐Ÿ’œ.


Status of This Memo

this memo is just giving info to the Internet community ๐Ÿซถ. It is NOT a standard of any kind, and it can be shared as much as you want with no limits ๐Ÿฆ‹.

Abstract

okay so SLP gives clients a brand new way to find network services on their own ๐Ÿ”ฅ. With SLP, it's super simple to offer highly available services that need zero user setup or help from network admins before anyone can use them ๐Ÿ’–. This doc describes standardized APIs for SLP in C and Java ๐Ÿ‘‘. The APIs are modular, so implementations only have to offer the features they actually need โœจ. It also defines standardized file formats for configuration and serialized registrations, so SLP agents can set network and other parameters in a portable way ๐ŸŒˆ. The serialized file format lets legacy services get registered with SLP directory agents when changing their program code is hard or impossible ๐Ÿ˜ญ, and it lets you swap a registration database between systems too ๐Ÿ“.

Table of Contents โœจ

    1. Introduction                                                    4
        1.1. Goals  . . . . . . . . . . . . . . . . . . . . . . . .    4
        1.2. Terminology  . . . . . . . . . . . . . . . . . . . . .    4
    2. File Formats                                                    7
        2.1. Configuration File Format  . . . . . . . . . . . . . .    8
              2.1.1. DA configuration   . . . . . . . . . . . . . .    9
              2.1.2. Static Scope Configuration . . . . . . . . . .    9
              2.1.3. Tracing and Logging  . . . . . . . . . . . . .   11
              2.1.4. Serialized Proxy Registrations . . . . . . . .   11
              2.1.5. Network Configuration Properties . . . . . . .   12
              2.1.6. SA Configuration . . . . . . . . . . . . . . .   14
              2.1.7. UA Configuration . . . . . . . . . . . . . . .   14
              2.1.8. Security   . . . . . . . . . . . . . . . . . .   15
        2.2. Multihomed Machines. . . . . . . . . . . . . . . . . .   16
        2.3. Serialized Registration File . . . . . . . . . . . . .   16
        2.4. Processing Serialized Registration and Configuration
             Files  . . . . . . . . . . . . . . . . . . . . . . . .   18
    3. Binding Independent Implementation Considerations              18
        3.1. Multithreading . . . . . . . . . . . . . . . . . . . .   18
        3.2. Asynchronous and Incremental . . . . . . . . . . . . .   19
        3.3. Type Checking for Service Types. . . . . . . . . . . .   19
        3.4. Refreshing Registrations . . . . . . . . . . . . . . .   19
        3.5. Configuration File Processing  . . . . . . . . . . . .   19
        3.6. Attribute Types  . . . . . . . . . . . . . . . . . . .   20
        3.7. Removal of Duplicates  . . . . . . . . . . . . . . . .   20
        3.8. Character Set Encoding . . . . . . . . . . . . . . . .   20
        3.9. Error Semantics  . . . . . . . . . . . . . . . . . . .   20
       3.10. Modular Implementations  . . . . . . . . . . . . . . .   24
       3.11. Handling Special Service Types . . . . . . . . . . . .   24
       3.12. Scope Discovery and Handling . . . . . . . . . . . . .   24
    4. C Language Binding                                             25
        4.1. Constant Types . . . . . . . . . . . . . . . . . . . .   26
              4.1.1. URL Lifetimes. . . . . . . . . . . . . . . . .   26
              4.1.2. Error Codes. . . . . . . . . . . . . . . . . .   26
              4.1.3. SLPBoolean . . . . . . . . . . . . . . . . . .   27
        4.2. Struct Types   . . . . . . . . . . . . . . . . . . . .   28
              4.2.1. SLPSrvURL  . . . . . . . . . . . . . . . . . .   28
              4.2.2. SLPHandle  . . . . . . . . . . . . . . . . . .   29
        4.3. Callbacks  . . . . . . . . . . . . . . . . . . . . . .   29
              4.3.1. SLPRegReport   . . . . . . . . . . . . . . . .   30
              4.3.2. SLPSrvTypeCallback . . . . . . . . . . . . . .   30
              4.3.3. SLPSrvURLCallback  . . . . . . . . . . . . . .   31
              4.3.4. SLPAttrCallback  . . . . . . . . . . . . . . .   33
        4.4. Opening and Closing an SLPHandle . . . . . . . . . . .   34
              4.4.1. SLPOpen. . . . . . . . . . . . . . . . . . . .   34
              4.4.2. SLPClose . . . . . . . . . . . . . . . . . . .   35
        4.5. Protocol API   . . . . . . . . . . . . . . . . . . . .   36
              4.5.1. SLPReg . . . . . . . . . . . . . . . . . . . .   36
              4.5.2. SLPDereg . . . . . . . . . . . . . . . . . . .   37
              4.5.3. SLPDelAttrs  . . . . . . . . . . . . . . . . .   38
              4.5.4. SLPFindSrvTypes. . . . . . . . . . . . . . . .   39
              4.5.5. SLPFindSrvs  . . . . . . . . . . . . . . . . .   41
              4.5.6. SLPFindAttrs . . . . . . . . . . . . . . . . .   42
        4.6. Miscellaneous Functions  . . . . . . . . . . . . . . .   43
              4.6.1. SLPGetRefreshInterval  . . . . . . . . . . . .   44
              4.6.2. SLPFindScopes  . . . . . . . . . . . . . . . .   44
              4.6.3. SLPParseSrvURL . . . . . . . . . . . . . . . .   45
              4.6.4. SLPEscape  . . . . . . . . . . . . . . . . . .   46
              4.6.5. SLPUnescape  . . . . . . . . . . . . . . . . .   47
              4.6.6. SLPFree  . . . . . . . . . . . . . . . . . . .   48
              4.6.7. SLPGetProperty . . . . . . . . . . . . . . . .   48
              4.6.8. SLPSetProperty . . . . . . . . . . . . . . . .   49
        4.7. Implementation Notes   . . . . . . . . . . . . . . . .   49

              4.7.1. Refreshing Registrations . . . . . . . . . . .   49
              4.7.2. Syntax for String Parameters . . . . . . . . .   49
              4.7.3. Client Side Syntax Checking  . . . . . . . . .   50
              4.7.4. System Properties  . . . . . . . . . . . . . .   50
              4.7.5. Memory Management  . . . . . . . . . . . . . .   51
              4.7.6. Asynchronous and Incremental Return Semantics.   51
        4.8. Example. . . . . . . . . . . . . . . . . . . . . . . .   52
    5. Java Language Binding                                          56
        5.1. Introduction . . . . . . . . . . . . . . . . . . . . .   56
        5.2. Exceptions and Errors  . . . . . . . . . . . . . . . .   56
              5.2.1. Class ServiceLocationException . . . . . . . .   57
        5.3. Basic Data Structures  . . . . . . . . . . . . . . . .   58
              5.3.1. Interface ServiceLocationEnumeration . . . . .   58
              5.3.2. Class ServiceLocationAttribute   . . . . . . .   58
              5.3.3. Class ServiceType  . . . . . . . . . . . . . .   61
              5.3.4. Class ServiceURL   . . . . . . . . . . . . . .   63
        5.4. SLP Access Interfaces  . . . . . . . . . . . . . . . .   67
              5.4.1. Interface Advertiser . . . . . . . . . . . . .   67
              5.4.2. Interface Locator  . . . . . . . . . . . . . .   69
        5.5. The Service Location Manager . . . . . . . . . . . . .   72
              5.5.1. Class ServiceLocationManager . . . . . . . . .   72
        5.6. Service Template Introspection . . . . . . . . . . . .   74
              5.6.1. Abstract Class TemplateRegistry  . . . . . . .   74
              5.6.2. Interface ServiceLocationAttributeVerifier . .   77
              5.6.3. Interface ServiceLocationAttributeDescriptor .   79
        5.7. Implementation Notes . . . . . . . . . . . . . . . . .   81
              5.7.1. Refreshing Registrations . . . . . . . . . . .   81
              5.7.2. Parsing Alternate Transports in ServiceURL . .   81
              5.7.3. String Attribute Values  . . . . . . . . . . .   82
              5.7.4. Client Side Syntax Checking. . . . . . . . . .   82
              5.7.5. Language Locale Handling . . . . . . . . . . .   82
              5.7.6. Setting SLP System Properties. . . . . . . . .   83
              5.7.7. Multithreading . . . . . . . . . . . . . . . .   83
              5.7.8. Modular Implementations  . . . . . . . . . . .   83
              5.7.9. Asynchronous and Incremental Return Semantics.   84
        5.8. Example. . . . . . . . . . . . . . . . . . . . . . . .   85
    6. Internationalization Considerations                            87
        6.1. service URL. . . . . . . . . . . . . . . . . . . . . .   87
        6.2. Character Set Encoding . . . . . . . . . . . . . . . .   87
        6.3. Language Tagging   . . . . . . . . . . . . . . . . . .   88
    7. Security Considerations                                        88
    8. Acknowledgements                                               88
    9. References                                                     89
   10. Authors' Addresses                                             90
   11. Full Copyright Statement                                       91

1. Introduction ๐Ÿฆ‹

okay so the Service Location API is built for standardized access to the Service Location Protocol (SLP) ๐Ÿ’…. It makes it way easier for client and service programs to be written or modified so they can do dynamic service discovery and selection ๐ŸŒธ. This document defines bindings for the C and Java languages ๐Ÿ‘‘. It also presents standardized formats for configuration files and serialized registration files ๐Ÿ“„. These files let SLP agents configure network parameters โš™๏ธ, register legacy services that aren't SLP enabled yet ๐Ÿ˜ญ, and swap registration databases between systems ๐Ÿ“.

1.1. Goals ๐ŸŽฏ

the big goal of the API is source portability ๐Ÿ’–: apps that use the API should be able to move between different SLP implementations with minimal fuss โœจ. That makes it easier to adopt SLP and to convert clients and service programs over to it ๐Ÿซถ.

the C binding is all about being minimal but still complete when it comes to the SLP protocol ๐Ÿงš. It keeps memory management simple and the code size small ๐Ÿ’œ.

the Java API is the fancier one ๐ŸŒˆ. It supports modular implementations, so you can leave out features you don't need, and it gives you an object oriented interface to the full set of SLP data and functionality ๐Ÿ”ฅ.

last thing: the standardized configuration and serialized file formats are simple to read but still cover the whole protocol ๐Ÿ‘‘. They just don't include system dependent properties or secure information ๐Ÿ™ˆ.

1.2. Terminology ๐Ÿ“š

okay bestie, here's the glossary, and it's giving "learn these or get lost" ๐Ÿ’… The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [1].

Service Location Protocol (SLP) ๐ŸŒธ

This is the underlying protocol that allows dynamic and scalable service discovery. It's specified in the Service Location Protocol Version 2 [7], so go read that if you're obsessed (I am) ๐Ÿค“

SLP framework ๐Ÿฆ‹

When someone says "Service Location framework," they mean both the SLP implementation and the interface implementation. Basically, whatever gives user-level programs their SLP functionality. This includes remote agents โœจ

Directory Agent (DA) ๐Ÿ‘‘

A service that automatically gathers service advertisements from SAs so it can hand them out to UAs. Main character energy, no cap ๐Ÿ’–

User Agent (UA) ๐Ÿงš

This is the Service Location process or library that makes SLP requests on behalf of a client process. UAs automatically send requests to DAs when they exist. When there aren't any, UAs make requests to SAs instead ๐Ÿซถ

Service Agent (SA) ๐Ÿ’œ

This is the Service Location process or library that lets service software register and deregister itself with the SLP framework. SAs respond to UA service requests, detect DAs, and register service advertisements with them. literally the hardest-working one ๐Ÿ˜ญ

SA Server ๐Ÿ”ฅ

Okay, this one's a plot twist. Many operating system platforms only allow a single process to listen on a particular port number. Since SAs are required to listen on a multicast address for SLP service requests, implementations of the SLP framework on those platforms that want to support multiple SAs on one machine need to arrange for a single process to do the listening, while the advertising SAs talk to that process through another mechanism. That single listening process is called an SA server. SA servers share many characteristics with DAs, but they are not the same ๐Ÿ™ˆ

Service Advertisement ๐Ÿ“

A URL, possibly combined with service attributes. SAs make these available to UAs, either directly or via a DA โœจ

Locale ๐ŸŒˆ

The language localization that applies to strings passed into or returned from the SLP API. The Locale is expressed using a Language Tag [6]. All attribute strings are associated with a particular locale. The locale is completely orthogonal to the ANSI C locale (not the same thing, bestie, don't mix them up ๐Ÿ’€). The SLP locale is mapped into the Java locale in the Java API.

Service Template ๐Ÿ“–

A document that describes the syntax of the URL for a given service type, plus a definition of all service attributes, including their meaning, defaults, and the constraints on the values they can take. See [8] for more information on service templates ๐Ÿ’…

The service: URL ๐ŸŽ€

A service of a particular type announces its availability with a service: URL. That URL includes its service access point (a domain name or IP address, and possibly its port number) and optionally some basic configuration parameters. The syntax of the service: URL is defined in the service template. Other URLs can be used in service advertisements if desired ๐Ÿฆ‹

Service Attributes ๐ŸŒธ

The attributes associated with a given service. The values that can be assigned to service attributes are defined by the service template โœจ

Scope ๐Ÿ’œ

A string used to control the availability of service advertisements. Every SLP Agent is configured with one or more scope strings. Site administrators assign scopes to group services for many purposes, but chiefly as a means of scalability. DAs store only services advertised with a scope string that matches the scopes they're configured with ๐Ÿ”ฅ

Naming Authority (NA) ๐Ÿ‘‘

This is a "suffix" to the service type string, and it completely changes the meaning of the service type. NAs are used for private definitions of well-known Service Types and for experimental Service Type extensions. The default NA is "IANA", which must not be explicitly included. Service types with the IANA naming authority are registered with the Internet Assigned Numbers Authority (see [8] for more information on the registration procedure) ๐ŸŒˆ


2. File Formats ๐Ÿ—‚๏ธ

This section describes the configuration and serialized registration file formats. Both files are defined in the UTF-8 character set [3] ๐Ÿ’–

Attribute tags and values in the serialized registration file require SLP reserved characters to be escaped. The SLP reserved characters are (, ), ,, \, !, <, =, >, ~ and control characters (characters with UTF codes less than 0x0020 and the character 0x007f, which is US-ASCII DEL). The escapes are formed exactly as they are for the wire protocol, i.e. a backslash followed by two hex digits representing the character. For example, the escape for , is \2c. In addition, the characters \n, \r, \t, and _ are prohibited from attribute tags by the SLP wire syntax grammar. [7] ๐Ÿง 

In serialized registration files, escaped strings beginning with \ff, an encoding for a nonUTF-8 character, are treated as opaques. Exactly as in the wire protocol, syntactically correct opaque encodings consist of a string beginning with \ff and containing only escaped characters that are transformed to bytes. Such strings are only syntactically correct in the serialized registration file as attribute values. In other cases, whenever an escape is encountered and the character is not an SLP reserved character, an error is signaled ๐Ÿšจ

Escaped characters in URLs in serialized registration files use the URL escape convention. [2] ๐ŸŒธ

Property names and values in the configuration file have a few reserved characters that are involved in the file's lexical definition. The characters . and = are reserved in property names and must be escape. The characters ,, (, and ) are reserved in property values and must be escaped. In addition, scope names in the net.slp.useScopes property use the SLP wire format escape convention for SLP reserved characters. This simplifies implementation, since the same code can be used to unescape scope names as is used when processing the serialized registration file or formatting wire messages ๐ŸŽ€

On platforms that only support US-ASCII and not UTF-8, the upper bit of bytes incoming from the configuration and registration files determines whether the character is US-ASCII or not US-ASCII. According to the standard UTF-8 encoding, the upper bit is zero if the character is US-ASCII and one if the character is multibyte and thus not US-ASCII. Platforms without intrinsic UTF-8 support are required to parse the multibyte character and store it in an appropriate internal format. Support for UTF-8 is required to implement the SLP protocol (see [7]), and can therefore be used in file processing as well ๐ŸŒˆ

The location and name of the configuration file is system-dependent, but implementations of the API are encouraged to locate it together with other configuration files and name it consistently โœจ

2.1. Configuration File Format โš™๏ธ

The configuration file format consists of a newline-delimited list of zero or more property definitions. Each property definition corresponds to a particular configurable SLP, network, or other parameter in one or more of the three SLP agents. The file format grammar in ABNF [5] syntax is:

   config-file   =  line-list
   line-list     =  line / line line-list
   line          =  property-line / comment-line
   comment-line  =  ( "#" / ";" ) 1*allchar newline
   property-line =  property newline
   property      =  tag "=" value-list
   tag           =  prop / prop "." tag
   prop          =  1*tagchar
   value-list    =  value / value "," value-list
   value         =  int / bool /
                    "(" value-list ")" / string
   int           =  1*DIGIT
   bool          =  "true" / "false" / "TRUE" / "FALSE"
   newline       =  CR / ( CRLF )
   string        =  1*stringchar
   tagchar       =  DIGIT / ALPHA / tother / escape
   tother        =  %x21-%x2d / %x2f /
                    %x3a / %x3c-%x40 /
                    %x5b-%x60 / %7b-%7e
                    ; i.e., all characters except `.',
                    ; and `='.
   stringchar    =  DIGIT / ALPHA / sother / escape
   sother        =  %x21-%x29 / %x2a-%x2b /
                    %x2d-%x2f / %x3a-%x40 /
                    %x5b-%x60 / %7b-%7e
                    ; i.e., all characters except `,'
   allchar       =  DIGIT / ALPHA / HTAB / SP
   escape        =  "\" HEXDIG HEXDIG
                    ; Used for reserved characters

With the exception of net.slp.useScopes, net.slp.DAAddresses, and net.slp.isBroadcastOnly, all other properties can be changed through property accessors in the C and Java APIs. The property accessors only change the property values in the running agent program and do not affect the values in the configuration file. The net.slp.useScopes and net.slp.DAAddresses properties are read-only, because they control the agent's view of the scopes and DAs and are therefore critical to the function of the API scope discovery algorithm. Attempts to modify them are unlikely to yield productive results, and could harm the ability of the agent to find scopes and use DAs. The net.slp.isBroadcastOnly property is read-only because the API library needs to configure networking upon start up, and changing this property might invalidate the configuration. Whether the local network uses broadcast or multicast is not likely to change during the course of the program's execution ๐Ÿ”’

The properties break down into the following subsections, each describing an area and its properties ๐Ÿงฉ

2.1.1. DA configuration ๐Ÿ‘‘

Important configuration properties for DAs are included in this section. These are:

net.slp.isDA ๐Ÿ’–

A boolean indicating if the SLP server is to act as a DA. If false, it does not run as a DA. Default is false.

net.slp.DAHeartBeat ๐Ÿ’œ

A 32 bit integer giving the number of seconds for the DA heartbeat. Default is 3 hours (10800 seconds). This property corresponds to the protocol specification parameter CONFIG_DA_BEAT [7]. Ignored if isDA is false โฐ

net.slp.DAAttributes ๐ŸŒธ

A comma-separated list of parenthesized attribute/value list pairs that the DA must advertise in DAAdverts. The property must be in the SLP attribute list wire format, including escapes for reserved characters. [7]

2.1.2. Static Scope Configuration โœจ

okay so these properties let you tweak how scopes get handled ๐ŸŽ€

net.slp.useScopes

This is a value-list of strings saying which scopes a UA or SA is allowed to use when it makes requests or registers, or which scopes a DA has to support. If it's not there for a DA or SA, then with no scope info from DHCP, the default scope "DEFAULT" gets used. If it's not there for a UA and DHCP has no scope info either, the user scoping model is in force ๐Ÿ’… Active and passive DA discovery or SA discovery handle scope discovery, and "DEFAULT" is the fallback if nothing else is available.

Now the spicy part ๐Ÿ”ฅ If a DA or SA gets a different scope in a request, it should return a SCOPE_NOT_SUPPORTED error, unless the request was multicast, in which case it should just drop it. If a DA gets another scope in a registration, it must return a SCOPE_NOT_SUPPORTED error. This property is "read-only" (no changing it after the config file has been read, those changes get ignored ๐Ÿ™…โ€โ™€๏ธ). See Section 3.12 for the algorithm the API uses to decide what scope info to present.

net.slp.DAAddresses

This is a value-list of IP addresses or DNS resolvable host names giving the SLPv2 DAs to use for statically configured UAs and SAs. DAs ignore it (unless the DA is also an SA server). The default is none. It's "read-only" too, so changes after the config file is read get ignored.

Here's the grammar for it ๐Ÿงš

addr-list     =  addr / addr "," addr-list
addr          =  fqdn / hostnumber
fqdn          =  ALPHA / ALPHA *[ anum / "-" ] anum
anum          =  ALPHA / DIGIT
hostnumber    =  1*3DIGIT 3("." 1*3DIGIT)

And an example:

sawah,mandi,sambal

IP addresses work where DNS isn't deployed, but network admins, be warned ๐Ÿ™ˆ using IP addresses makes renumbering machines a headache, since the SLP config property files in statically configured networks will have to be changed. And if you use host names, implementors must be careful that a name service is up before SLP starts. In other words, SLP can't be used to find the name service. Bestie, that's a chicken-and-egg situation ๐Ÿ’€


2.1.3. Tracing and Logging ๐Ÿฆ‹

This section lets the various agents print tracing and logging info.

net.slp.traceDATraffic

A boolean that controls printing of messages about traffic with DAs. Default is false.

net.slp.traceMsg

A boolean that controls printing of details on SLP messages. All fields in incoming messages and outgoing replies get printed. Default is false.

net.slp.traceDrop

A boolean that controls printing details when an SLP message gets dropped for any reason. Default is false.

net.slp.traceReg

A boolean that controls dumps of all registered services upon registration and deregistration. If true, the contents of the DA or SA server get dumped after a registration or deregistration happens. Default is false.


2.1.4. Serialized Proxy Registrations ๐ŸŒธ

These properties control reading and writing serialized registrations.

net.slp.serializedRegURL

A string containing a URL that points to a document with serialized registrations, which should be processed when the DA or SA server starts up. Default is none.


2.1.5. Network Configuration Properties ๐ŸŒˆ

The properties in this section let you set various network configuration properties.

net.slp.isBroadcastOnly

A boolean saying whether broadcast should be used instead of multicast. Like net.slp.useScopes and net.slp.DAAddresses, this one is "read-only", so changes after the config file has been read get ignored. Default is false.

net.slp.passiveDADetection

A boolean saying whether passive DA detection should be used. Default is true.

net.slp.multicastTTL

A positive integer less than or equal to 255, giving the multicast TTL. Default is 255.

net.slp.DAActiveDiscoveryInterval

A 16 bit positive integer giving the number of seconds between DA active discovery queries. Default is 900 seconds (15 minutes). This property corresponds to the protocol specification parameter CONFIG_DA_FIND [7]. If it's set to zero, active discovery is turned off. That's useful when the DAs available are explicitly restricted to those obtained from DHCP or the net.slp.DAAddresses property ๐ŸŽฏ

net.slp.multicastMaximumWait

A 32 bit integer giving the maximum amount of time to perform multicast, in milliseconds. Default is 15000 ms (15 sec.). This property corresponds to the CONFIG_MC_MAX parameter in the protocol specification [7].

net.slp.multicastTimeouts

A value-list of 32 bit integers used as timeouts, in milliseconds, to implement the multicast convergence algorithm. Each value is the time to wait before sending the next request, or until nothing new has been learned from two successive requests. Default is:

3000,3000,3000,3000,3000

In a fast network, the aggressive values of

1000,1250,1500,2000,4000

allow better performance โšก This property corresponds to the CONFIG_MC_RETRY parameter in the protocol specification [7]. Note that the net.slp.DADiscoveryTimeouts property must be used for active DA discovery.

net.slp.DADiscoveryTimeouts

A value-list of 32 bit integers used as timeouts, in milliseconds, to implement the multicast convergence algorithm during active DA discovery. Each value is the time to wait before sending the next request, or until nothing new has been learned from two successive requests. This property corresponds to the protocol specification parameter CONFIG_RETRY [7]. Default is:

2000,2000,2000,2000,3000,4000

net.slp.datagramTimeouts

A value-list of 32 bit integers used as timeouts, in milliseconds, to implement unicast datagram transmission to DAs. The nth value is the time to block waiting for a reply on the nth try to contact the DA. The sum of these values is the protocol specification property CONFIG_RETRY_MAX [7].

net.slp.randomWaitBound

A 32 bit integer giving the maximum value for all random wait parameters, in milliseconds. Default is 1000 (1 sec.). This value corresponds to the protocol specification parameters CONFIG_START_WAIT, CONFIG_REG_PASSIVE, and CONFIG_REG_ACTIVE [7].

net.slp.MTU

A 16 bit integer giving the network packet MTU, in bytes. This is the maximum size of any datagram to send, but the implementation might receive a larger datagram. The maximum size includes IP, and UDP or TCP headers. Default is 1400.

net.slp.interfaces

A value-list of strings giving the IP addresses of network interfaces that the DA or SA should listen on, on port 427, for multicast, unicast UDP, and TCP messages. Default is empty, i.e. use the default network interface. The grammar for this property is:

addr-list     =  hostnumber / hostnumber "," addr-list
hostnumber    =  1*3DIGIT 3("." 1*3DIGIT)

An example is:

195.42.42.42,195.42.142.1,195.42.120.1

The example machine has three interfaces the DA should listen on. Since this property only takes IP addresses, it'll need to be changed if the network gets renumbered ๐Ÿ”„


2.1.6. SA Configuration ๐Ÿง

This section has the configuration properties for the SA. These are typically set programmatically by the SA, since they're specific to each SA.

net.slp.SAAttributes

A comma-separated list of parenthesized attribute/value list pairs that the SA must advertise in SAAdverts. The property must be in the SLP attribute list wire format, including escapes for reserved characters. [7]


2.1.7. UA Configuration ๐Ÿ’œ

This section has the configuration properties for the UA. These can be set either programmatically by the UA or in the configuration file.

net.slp.locale

A RFC 1766 Language Tag [6] for the language locale. Setting this property makes its value the default locale for SLP messages. Default is "en". This property is also used for SA and DA configuration.

net.slp.maxResults

A 32 bit integer giving the maximum number of results to accumulate and return for a synchronous request before the timeout, or the maximum number of results to return through a callback if the request results are reported asynchronously.

Positive integers and -1 are legal values. If it's -1, that means all results should be returned. Default value is -1.

DAs and SAs always return all results that match the request. This config value only applies to UAs, which filter incoming results and only return as many values as net.slp.maxResults indicates ๐Ÿ”

net.slp.typeHint

A value-list of service type names. Without any DAs, UAs perform SA discovery to find scopes. These SA discovery requests may contain a request for service types as an attribute.

The API implementation will use the service type names supplied by this property to discover only those SAs (and their scopes) that support the desired service type or types. For example, if net.slp.typeHint is set to "service:imap,service:pop3", then SA discovery requests will include the search filter:

(|(service-type=service:imap)(service-type=service:pop3))

The API library can also use unicast to contact the discovered SAs for later requests for these service types, to optimize network access ๐Ÿš€


2.1.8. Security ๐Ÿ”

The property in this section turns security for all agents on or off. When it's true, the agent must include security information on all SLP messages it transacts. Since security policy has to be set network wide to work, a single property controls security for all agents. Key management and management of SLP SPI strings [7] are implementation and policy dependent, so that's on you ๐Ÿซถ

net.slp.securityEnabled

A boolean saying whether the agent should enable security for URLs, attribute lists, DAAdverts, and SAAdverts. Each agent is responsible for interpreting the property appropriately. Default is false.

2.2. Multihomed Machines ๐ŸŒโœจ

okay so on multihomed machines (aka boxes with more than one network interface, bestie ๐Ÿ’ป), each interface can have totally different bandwidth and latency, so one set of settings might not be the best fit for all of them ๐Ÿฅบ that's why net.slp.interfaces exists. It tells you which interfaces are SLP enabled ๐ŸŽ€ An API library can even customise things per interface by adding the interface IP address onto the end of a property name. When it does that, the value only applies to that one interface, and the generic property (or the defaults, if there's no generic one) covers everything else ๐Ÿ’…

here's an example so you can see the vibe:

net.slp.interfaces=125.196.42.41,125.196.42.42,125.196.42.43
net.slp.multicastTTL.125.196.42.42=1

so the interface on subnet 42 gets locked to a TTL of 1 ๐Ÿฆ‹ while the interfaces on the other subnets keep the default multicast radius, which is 255 ๐Ÿ’œ

now the big rules ๐Ÿ‘€ net.slp.interfaces should only be set if there's no routing between the interfaces. if it is set, the DA (if there is one) and the SAs should advertise using the IP address or host name that matches the interface they're on, for every interface in the list ๐ŸŒธ but if packets get routed between the interfaces, then the DA and SAs should only advertise on the default interface. the property should also be set if broadcast is used instead of multicast on the subnets attached to those interfaces ๐Ÿ“

and here's the tea โ˜• even if unicast packets aren't routed between the interfaces, multicast might still get routed through some other router ๐Ÿ™ˆ the danger of listening for multicast on several interfaces when multicast gets routed is that the DA or SA could receive the same multicast request through more than one interface. since the IP address is different on each interface, the DA or SA can't tell that the request was already answered via the previous responder's list ๐Ÿ˜ญ so the requesting agent ends up with URLs that point at the same DA or service, but with different addresses or host names. not it ๐Ÿ’€


2.3. Serialized Registration File ๐Ÿ“œ๐Ÿซถ

the serialized registration file holds a group of registrations that a DA or SA server (if one exists) registers when it starts up ๐Ÿงš these are mainly for older service programs that don't support SLP internally and can't be converted, and for swapping registrations between SLP implementations in a portable way ๐Ÿ’œ the character encoding of the registrations is required to be UTF-8 ๐ŸŒˆ

here's the ABNF grammar (ABNF format [5]) for the file, so you know exactly what's allowed:

ser-file      =  reg-list
reg-list      =  reg / reg reg-list
reg           =  creg / ser-reg
creg          =  comment-line ser-reg
comment-line  =  ( "#" / ";" ) 1*allchar newline
ser-reg       =  url-props [slist] [attr-list] newline
url-props     =  surl "," lang "," ltime [ "," type ] newline
surl          =  ;The registration's URL. See
                 ; [8] for syntax.
lang          =  1*8ALPHA [ "-" 1*8ALPHA ]
                 ;RFC 1766 Language Tag see [6].
ltime         =  1*5DIGIT
                 ; A positive 16-bit integer
                 ; giving the lifetime
                 ; of the registration.
type          =  ; The service type name, see [7]
                 ; and [8] for syntax.
slist         =  "scopes" "=" scope-list newline
scope-list    =  scope-name / scope-name "," scope-list
scope         =  ; See grammar of [7] for
                 ; scope-name syntax.
attr-list     =  attr-def / attr-def attr-list
attr-def      =  ( attr / keyword ) newline
keyword       =  attr-id
attr          =  attr-id "=" attr-val-list
attr-id       =  ;Attribute id, see [7] for syntax.
attr-val-list =  attr-val / attr-val "," attr-val-list
attr-val      =  ;Attribute value, see [7] for syntax.
allchar       =  char / WSP
char          =  DIGIT / ALPHA / other
other         =  %x21-%x2f / %x3a-%x40 /
                 %x5b-%x60 / %7b-%7e
                 ; All printable, nonwhitespace US-ASCII
                 ; characters.
newline       =  CR / ( CRLF )

the syntax for scope names, attribute tags and attribute values needs escapes for special characters, as specified in [7] ๐Ÿ” DAs and SA servers that process serialized registrations have to handle them exactly as if an SA had registered them ๐Ÿฆ‹ in the url-props production, the type token is optional ๐ŸŒธ if the type token is there for a service: URL, a warning gets signalled and the type name gets ignored โš ๏ธ if the maximum lifetime is given (65535 sec.), the registration counts as permanent, and the DA or SA server keeps refreshing it until it exits ๐Ÿ’–

scopes can be added to a registration by including an attribute definition with the tag "scopes", followed by a comma separated list of scope names right after the url-props production โœจ if that optional scope list is there, the registrations get made in the scopes listed; otherwise they go into the scopes the DA or SA server was configured with through the net.slp.useScopes property ๐ŸŽ€

one more thing ๐Ÿ‘€ if the scope list has scopes that aren't in the net.slp.useScopes property (assuming that property is set), or aren't specified by DHCP, the API library should reject the registration and issue a warning message ๐Ÿšซ

2.4. Processing Serialized Registration and Configuration Files โš™๏ธ๐ŸŒท

implementations are encouraged to make processing of configuration and serialized files as transparent as possible to API clients ๐Ÿซถ errors must be caught at the latest when the relevant configuration item gets used ๐Ÿ•ฐ๏ธ and they may be caught at the earliest when the relevant file is loaded into the executing agent โœจ errors should be reported by logging to the appropriate platform logging file, error output, or log device, and the default value gets substituted ๐Ÿ’… serialized registration file entries should be caught and reported when the file is loaded ๐Ÿ“œ

configuration file loading must be complete before the first networking connection is started ๐ŸŒ and serialized registration must be complete before the DA accepts the first network request ๐Ÿ”ฅ


3. Binding Independent Implementation Considerations ๐Ÿงฉ๐Ÿ’–

this section talks about a bunch of implementation considerations that don't depend on the language binding, with notes for specific languages where they apply ๐Ÿฆ‹

3.1. Multithreading ๐Ÿงต

implementations of both the C and Java APIs are required to make API calls thread-safe ๐Ÿ’œ access to data structures shared between threads has to be coordinated so nothing gets corrupted or accessed invalidly ๐Ÿ˜ญ one way to get there is to allow only one thread at a time in the implementing library, but performance in that kind of implementation takes a hit ๐Ÿข so wherever possible, implementations are encouraged to allow multiple threads inside the SLP API library ๐Ÿš€

3.2. Asynchronous and Incremental ๐ŸŒŠ

the APIs are designed to encourage implementations that support asynchronous and incremental client interaction โœจ the goal is to let big numbers of returned service URLs, service types and attributes come back without having to allocate huge chunks of memory ๐Ÿง  the particular design features that support this differ between the two language bindings ๐ŸŒˆ

3.3. Type Checking for Service Types ๐Ÿ”

service templates [8] let SLP registrations be type checked for correctness ๐ŸŽ€ implementations of the API are free to use service type information for type checking, but they aren't required to ๐Ÿ™Œ if a type error does happen, the registration should terminate with TYPE_ERROR โŒ

3.4. Refreshing Registrations ๐Ÿ”„๐Ÿ’ซ

SLP advertisements carry an explicit lifetime with them ๐Ÿ•ฐ๏ธ once the lifetime runs out, the DA flushes the registration from its cache ๐Ÿงน sometimes an application wants its URL to stay registered for the whole time it's running, so the API has a way for clients to say whether they want URLs refreshed automatically ๐Ÿ’– implementations of the SA API must provide this automatic refreshing capability ๐Ÿซถ a client using this feature should explicitly deregister the service URL before exiting ๐Ÿšช the reason is that the API implementation may not be able to make sure the URL gets deregistered when the application exits, though it will eventually time out in the DA ๐Ÿ’€

3.5. Configuration File Processing ๐Ÿ› ๏ธ

DAs, SAs and UAs that process the configuration file, and DAs and SA servers that process the serialized registration file, are required to log any errors using whatever underlying error mechanism is appropriate for the platform ๐Ÿ“ examples include writing error messages to standard output, writing to a system logging device, or showing the errors in a logging window ๐ŸชŸ after the error is reported, the offending property must be set to the default and program execution continued ๐Ÿ” An agent MUST NOT fail if a file format error occurs. ๐Ÿซ ๐Ÿ’œ

3.6. Attribute Types ๐Ÿท๏ธ

string encoded attribute values don't include explicit type information ๐Ÿคท all UA implementations, and those SA and DA implementations that choose to support type checking, should use the type rules described in [8] to convert from the string representation on the wire into an object with the appropriate type ๐ŸŽ€

3.7. Removal of Duplicates ๐Ÿ‘ฏโ€โ™€๏ธ

the UA implementation SHOULD always collate results to remove duplicates during synchronous operations and for the Java API ๐Ÿงน during asynchronous operation in C, the UA implementation SHOULD forgo duplicate elimination to reduce memory requirements in the library ๐Ÿง  this lets the API library just take the returned attribute value list strings, URL strings or service type list strings and call the callback function with them, with no extra processing ๐Ÿš€ naturally, the burden of duplicate elimination then falls on the client ๐Ÿ˜…

3.8. Character Set Encoding ๐Ÿ”ค๐ŸŒ

character string parameters in the Java API are all represented in Unicode internally, because that's the character set Java supports ๐Ÿ’œ character buffer parameters in the C API are represented in UTF-8, so they stay maximally compatible on platforms that only support US-ASCII and not UTF-8 ๐ŸŒธ API functions still have to handle the full range of UTF-8 characters because the SLP protocol requires it, but the API implementation can store the characters internally in any convenient way ๐Ÿงš on the wire, all characters are converted to UTF-8 ๐Ÿ“ก inside URLs, characters that URL syntax [2] doesn't allow must be escaped according to the URL escape character convention ๐Ÿ” strings included in SLP messages may contain SLP reserved characters, and clients can escape them through convenience functions the API provides ๐ŸŽ€ the character encoding used in escapes is UTF-8 ๐Ÿ’–

due to constraints in SLP, no string parameter passed to the C or Java API may exceed 64K bytes in length ๐Ÿ“๐Ÿ™ƒ

3.9. Error Semantics โœจ

Okay so, every error that pops up while processing SLP messages should get logged ๐Ÿ“. That's non-negotiable bestie.

For synchronous calls, an error only gets reported on a call if no successful replies came back from any SLP framework entity. If one error showed up among several successful replies, log it and still return the good replies ๐Ÿ’… (the vibe is "the tea is logged, but the wins still count").

For asynchronous calls, an error that happens while talking to a particular remote SLP agent gets reported through the first callback (C API) or enumeration method invocation (Java API) after the error happens, which is usually where the results of that conversation get reported too. That way the callback or client code can decide whether to terminate or keep going ๐Ÿฆ‹. Some errors from the SLP framework are fatal (SLP_PARSE_ERROR, etc.) and in those cases the API library terminates the operation ๐Ÿ’€.

Both the Java and C APIs have language-specific error code mechanisms for returning error info ๐ŸŽ€. The names of the error codes match between the two implementations though, so that's one less thing to memorize ๐Ÿซถ.

The following error codes are returned from a remote agent (DA or SA server):

  • LANGUAGE_NOT_SUPPORTED: No DA or SA has service advertisement or attribute information in the language requested, but at least one DA or SA indicated, via the LANGUAGE_NOT_SUPPORTED error code, that it might have information for that service in another language.
  • PARSE_ERROR: The SLP message was rejected by a remote SLP agent. The API returns this error only when no information was retrieved, and at least one SA or DA indicated a protocol error. The data supplied through the API may be malformed or may have been damaged in transit.
  • INVALID_REGISTRATION: The API may return this error if an attempt to register a service was rejected by all DAs because of a malformed URL or attributes. SLP does not return the error if at least one DA accepted the registration.
  • AUTHENTICATION_ABSENT: If the SLP framework supports authentication, this error arises when the UA or SA failed to send an authenticator for requests or registrations in a protected scope.
  • INVALID_UPDATE: An update for a non-existing registration was issued, or the update includes a service type or scope different than that in the initial registration, etc.

The following errors result from interactions with remote agents or can occur locally:

  • AUTHENTICATION_FAILED: If the SLP framework supports authentication, this error arises when an authentication on an SLP message failed.
  • SCOPE_NOT_SUPPORTED: The API returns this error if the SA has been configured with the net.slp.useScopes value-list of scopes and the SA request did not specify one or more of these allowable scopes, and no others. It may be returned by a DA or SA if the scope included in a request is not supported by the DA or SA.
  • REFRESH_REJECTED: The SA attempted to refresh a registration more frequently than the minimum refresh interval. The SA should call the appropriate API function to obtain the minimum refresh interval to use.

The following errors are generated through a program interacting with the API implementation. They do not involve a remote SLP agent.

  • NOT_IMPLEMENTED: If an unimplemented feature is used, this error is returned.
  • NETWORK_INIT_FAILED: If the network cannot initialize properly, this error is returned.
  • NETWORK_TIMED_OUT: When no reply can be obtained in the time specified by the configured timeout interval for a unicast request, this error is returned.
  • NETWORK_ERROR: The failure of networking during normal operations causes this error to be returned.
  • BUFFER_OVERFLOW: An outgoing request overflowed the maximum network MTU size. The request should be reduced in size or broken into pieces and tried again.
  • MEMORY_ALLOC_FAILED: If the API fails to allocate memory, the operation is aborted and returns this.
  • PARAMETER_BAD: If a parameter passed into an interface is bad, this error is returned.
  • INTERNAL_SYSTEM_ERROR: A basic failure of the API causes this error to be returned. This occurs when a system call or library fails. The operation could not recover.
  • HANDLE_IN_USE: In the C API, callback functions are not permitted to recursively call into the API on the same SLPHandle, either directly or indirectly. If an attempt is made to do so, this error is returned from the called API function.
  • TYPE_ERROR: If the API supports type checking of registrations against service type templates, this error can arise if the attributes in a registration do not match the service type template for the service.

Some error codes are handled differently in the Java API. These differences are discussed in Section 5.

The SLP protocol errors OPTION_NOT_UNDERSTOOD, VERSION_NOT_SUPPORTED, INTERNAL_ERROR, MSG_NOT_SUPPORTED, AUTHENTICATON_UNKNOWN, and DA_BUSY_NOW should be handled internally and not surfaced to clients through the API ๐Ÿ™ˆ.


3.10. Modular Implementations ๐Ÿงฉ

Okay, subset implementations that don't support the full range of functionality are required to still support every interface ๐Ÿซถ. Why? Because it keeps link compatibility between compliant API implementations and applications intact. So if a particular operation isn't supported, a NOT_IMPLEMENTED error should be returned.

The Java API has some extra conventions for handling subsets. And applications that are expected to run on a wide variety of platforms should be prepared for subset API implementations by checking the error codes they get back ๐ŸŒˆ.


3.11. Handling Special Service Types ๐Ÿ•ต๏ธโ€โ™€๏ธ

The service types service:directory-agent and service:service-agent are used internally in the SLP framework to discover DAs and SAs. Normally the API client never sees this discovery mechanism ๐Ÿ™ˆ. BUT the client might still care about discovering DAs and SAs on their own, separate from their role in finding other services. For example, a network management app might want to figure out which machines are running SLP DAs ๐Ÿ’œ. So API implementations must handle requests to find services and attributes for these two service types, so that API clients get the info they expect โœจ.

Here's the catch: if the UA is using a DA, SrvRqst and AttrRqst for these service types must be multicast and not unicast to the DA, unlike other service types ๐Ÿ’€. If the requests aren't multicast, the DA will respond with an empty reply to a request for services of type service:service-agent, and with its URL only to a request for services of type service:directory-agent. So the UA wouldn't get the full picture of the available DAs and SAs. Not a vibe ๐Ÿ˜ญ.


3.12. Scope Discovery and Handling ๐Ÿ—บ๏ธ

Both APIs have an operation to get a list of currently known scope names ๐ŸŽ€. That scope info comes from a bunch of places: DHCP, the net.slp.useScopes property, unicast to DAs configured via DHCP or the net.slp.DAAddresses property, and active and passive discovery.

The API is required to be implemented in a way that re-enforces the administrative and user scoping models described in [7]. SA clients only support the administrative scoping model. SAs must know a priori what DAs they need to register with, since there's typically no human intervention in scope selection for SAs ๐Ÿค–. UAs must support both administrative and user scoping, because an application may require human intervention in scope selection ๐Ÿ‘‘.

API implementations are required to support administrative scoping in the following way. Scopes configured by DHCP and scopes of DAs configured by DHCP have first priority (in that order) and must be returned if they're available. The net.slp.useScopes property has second priority, and scopes discovered through the net.slp.useScopes property must be returned if this property is set and there are no scopes available from DHCP. If scopes aren't available from either of these sources and the net.slp.DAAddresses property is set, then the scopes available from the configured DAs must be returned. Note that if both DAs and scopes are configured, the scopes of the configured DAs must match the configured scope list; otherwise an error is signaled and agent execution is terminated ๐Ÿšจ. If no configured scope information is available, then an SA client has default scope, "DEFAULT", and a UA client employs user scoping.

User scoping is supported in the following way. Scopes discovered from active DA discovery, and from passive DA discovery, all must be returned. If no information is available from active and passive DA discovery, then the API library may perform SA discovery, using the service types in the net.slp.typeHint property to limit the search to SAs supporting particular service types. If no net.slp.typeHint property is set, the UA may perform SA discovery without any service type query. In the absence of any of the above sources of information, the API must return the default scope, "DEFAULT". Note that the API must always return some scope information ๐Ÿซง.

SLP requires that SAs must perform their operations in all scopes currently known to them. [7]. The API enforces this constraint by not requiring the API client to supply any scopes as parameters to API operations. The API library must obtain all currently known scopes and use them in SA operations. UA API clients should use a scope obtained through one of the API operations for finding scopes. Any other scope name may result in a SCOPE_NOT_SUPPORTED error from a remote agent. The UA API library can optionally check the scope and return the error without contacting a remote agent ๐Ÿฆ‹.


4. C Language Binding ๐Ÿ’ป

The C language binding is a minimal overhead implementation that maps directly into the protocol ๐Ÿ“. There's one C language function per protocol request, with the exception of the SLPDereg() and SLPDelAttrs() functions, which map into different uses of the SLP deregister request. Parameters are mostly character buffers. Memory management is kept simple by having the client allocate most of the memory, and requiring that client callback functions copy incoming parameters into memory allocated by the client code. Any memory returned directly from the API functions is deallocated using the SLPFree() function ๐Ÿงน.

To conform with standard C practice, all character strings passed to and returned through the API are null terminated, even though the SLP protocol doesn't use null terminated strings ๐Ÿค“. Strings passed as parameters are UTF-8, but they may still be passed as a C string (a null terminated sequence of bytes). Escaped characters must be encoded by the API client as UTF-8. In the common case of US-ASCII, the usual one byte per character C strings work. API functions help with escaping and unescaping strings ๐Ÿ’–.

Unless otherwise noted, parameters to API functions and callbacks are non-NULL. Some parameters may have other restrictions. If any parameter fails to satisfy the restrictions on its value, the operation returns a PARAMETER_BAD error ๐Ÿšซ.

4.1. Constant Types ๐ŸŒธ

4.1.1. URL Lifetimes ๐Ÿ•ฐ๏ธ

4.1.1.1. Synopsis

typedef enum {
  SLP_LIFETIME_DEFAULT = 10800,
  SLP_LIFETIME_MAXIMUM = 65535
} SLPURLLifetime;

4.1.1.2. Description

Okay bestie, the SLPURLLifetime enum holds the URL lifetime values (in seconds) that everyone keeps reaching for โฐโœจ. SLP_LIFETIME_DEFAULT is 3 hours, and SLP_LIFETIME_MAXIMUM is about 18 hours. That max is the biggest number the lifetime field can hold in SLP messages, so it's basically the ceiling ๐Ÿ™ˆ๐Ÿ’…

4.1.2. Error Codes

4.1.2.1. Synopsis

typedef enum {
  SLP_LAST_CALL                    = 1,
  SLP_OK                           = 0,
  SLP_LANGUAGE_NOT_SUPPORTED       = -1,
  SLP_PARSE_ERROR                  = -2,
  SLP_INVALID_REGISTRATION         = -3,
  SLP_SCOPE_NOT_SUPPORTED          = -4,
  SLP_AUTHENTICATION_ABSENT        = -6,
  SLP_AUTHENTICATION_FAILED        = -7,
  SLP_INVALID_UPDATE               = -13,
  SLP_REFRESH_REJECTED             = -15,
  SLP_NOT_IMPLEMENTED              = -17,
  SLP_BUFFER_OVERFLOW              = -18,
  SLP_NETWORK_TIMED_OUT            = -19,
  SLP_NETWORK_INIT_FAILED          = -20,
  SLP_MEMORY_ALLOC_FAILED          = -21,
  SLP_PARAMETER_BAD                = -22,
  SLP_NETWORK_ERROR                = -23,
  SLP_INTERNAL_SYSTEM_ERROR        = -24,
  SLP_HANDLE_IN_USE                = -25,
  SLP_TYPE_ERROR                   = -26
} SLPError ;

4.1.2.2. Description

The SLPError enum is the list of error codes that API functions hand back to you ๐Ÿšจ

SLP_OK means that no error happened during the operation. Yay, all good ๐ŸŽ€

SLP_LAST_CALL is the one that gets passed to callback functions when the API library has run out of data for them. After that, no more calls will come in on the operation that's still outstanding ๐Ÿ›‘ The callback can use this as a signal to tell the main client code that more data isn't coming, so the main body can break out of its data-collection loops. During both a synchronous and an asynchronous call, the last callback call has the error code parameter set to SLP_LAST_CALL, and all the other parameters are NULL. If an API operation returns no results, then there's only one call, and its error parameter is SLP_LAST_CALL ๐Ÿ’œ

4.1.3. SLPBoolean

4.1.3.1. Synopsis

typedef enum {
   SLP_FALSE = 0,
   SLP_TRUE = 1

} SLPBoolean;

4.1.3.2. Description

SLPBoolean is the enum you use as a true-or-false flag โœ…โŒ

4.2. Struct Types

4.2.1. SLPSrvURL

4.2.1.1. Synopsis

typedef struct srvurl {
  char *s_pcSrvType;
  char *s_pcHost;
  int   s_iPort;
  char *s_pcNetFamily;
  char *s_pcSrvPart;
} SLPSrvURL;

4.2.1.2. Description

SLPSrvURL is filled in by the SLPParseSrvURL() function. It takes information parsed out of a character buffer that holds a service URL, and each field matches a different part of that URL ๐Ÿงฉ Fun fact: this struct follows the standard Berkeley sockets struct servent, with one twist. The pointer to an array of characters for aliases (the s_aliases field) gets swapped out for a pointer to the host name (the s_pcHost field) ๐ŸŒธ

  • s_pcSrvType A pointer to a character string with the service type name, including the naming authority. The service type name includes the "service:" if the URL uses the service: scheme. [7]
  • s_pcHost A pointer to a character string with the host identification information.
  • s_iPort The port number, or zero if there isn't one. The port only exists if the transport is IP.
  • s_pcNetFamily A pointer to a character string with the network address family identifier. The possible values are "ipx" for the IPX family, "at" for the Appletalk family, and "" (that's the empty string) for the IP address family ๐Ÿฆ‹
  • s_pcSrvPart Whatever is left of the URL after the host identification.

The host and port should be enough to open a socket to the machine hosting the service. The rest of the URL should let you tell the service apart from others ๐Ÿซถ

4.2.2. SLPHandle

4.2.2.1. Synopsis

typedef void* SLPHandle;

SLPHandle is what SLPOpen() gives you back, and it's a parameter for every SLP function โœจ It works like a handle for all the resources the SLP library allocates on behalf of the process. The type is opaque, because what it actually is depends on the implementation ๐Ÿ™ˆ

4.3. Callbacks

When you call an API function, you include a function pointer to a callback that's specific to that operation in the parameter list. The callback gets called with the results of the operation in both the synchronous and asynchronous cases ๐Ÿ“ž The memory in the callback parameters belongs to the API library. So if the client code in the callback wants to keep that info around for longer than the current callback call, it must copy it out ๐Ÿ’…

Every callback parameter list also has an error code parameter and a cookie parameter. The error code reports the error status of the ongoing operation (for asynchronous) or the completed operation (for synchronous) ๐Ÿšฆ The cookie lets the client code that starts the operation pass info down to the callback without needing global variables, which is so clean ๐Ÿ“ The callback returns an SLPBoolean to say whether the API library should keep processing the operation. If the callback returns SLP_TRUE, asynchronous operations get terminated. Synchronous operations ignore the return value, since they're already complete ๐ŸŒˆ

4.3.1. SLPRegReport

4.3.1.1. Synopsis

typedef void SLPRegReport(SLPHandle hSLP,
                          SLPError errCode,
                          void *pvCookie);

4.3.1.2. Description

SLPRegReport is the callback type for SLPReg(), SLPDereg(), and SLPDelAttrs() ๐ŸŽ€

4.3.1.3. Parameters

  • hSLP The SLPHandle that started the operation.
  • errCode An error code that tells you if something went wrong during the operation.
  • pvCookie Memory the client code passed down from the original API function call that started the operation. It may be NULL.

4.3.2. SLPSrvTypeCallback

4.3.2.1. Synopsis

typedef SLPBoolean SLPSrvTypeCallback(SLPHandle hSLP,
                                      const char* pcSrvTypes,
                                      SLPError errCode,
                                      void *pvCookie);

4.3.2.2. Description

SLPSrvTypeCallback is the callback type you pass to the SLPFindSrvTypes() function ๐Ÿ” If the hSLP handle was opened asynchronously, the results that come back through the callback MAY be uncollated ๐ŸŒ€ If it was opened synchronously, then the results must be collated and the duplicates have to be eliminated ๐Ÿงน

4.3.2.3. Parameters

  • hSLP The SLPHandle that started the operation.
  • pcSrvTypes A character buffer with a comma-separated, null-terminated list of service types ๐Ÿ“‹
  • errCode An error code that tells you if something went wrong during the operation. The callback should check this error code before it processes the parameters. If the error code is anything other than SLP_OK, then the API library may choose to end the outstanding operation ๐Ÿ›‘
  • pvCookie Memory the client code passed down from the original API function call that started the operation. It may be NULL.

4.3.2.4. Returns

The client code should return SLP_TRUE if it wants more data. Otherwise, it returns SLP_FALSE ๐Ÿ™‹โ€โ™€๏ธ

4.3.3. SLPSrvURLCallback

4.3.3.1. Synopsis

typedef SLPBoolean SLPSrvURLCallback(SLPHandle hSLP,
                                     const char* pcSrvURL,
                                     unsigned short sLifetime,
                                     SLPError errCode,
                                     void *pvCookie);

4.3.3.2. Description

SLPSrvURLCallback is the callback type you pass to the SLPFindSrvs() function ๐Ÿงš If the hSLP handle was opened asynchronously, the results that come back through the callback MAY be uncollated ๐ŸŒธ If it was opened synchronously, the results must be collated and the duplicates eliminated ๐Ÿ’…

4.3.3.3. Parameters

  • hSLP The SLPHandle that started the operation.
  • pcSrvURL A character buffer with the returned service URL ๐Ÿ”—
  • sLifetime An unsigned short with the lifetime of the service advertisement, in seconds. The value must be an unsigned integer that is less than or equal to SLP_LIFETIME_MAXIMUM โณ
  • errCode An error code that tells you if something went wrong during the operation. The callback should check this error code before it processes the parameters. If the error code is anything other than SLP_OK, then the API library may choose to end the outstanding operation ๐Ÿšจ
  • pvCookie Memory the client code passed down from the original API function call that started the operation. It may be NULL.

4.3.3.4. Returns

The client code should return SLP_TRUE if it wants more data. Otherwise, it returns SLP_FALSE ๐Ÿ™Œ

4.3.4. SLPAttrCallback

4.3.4.1. Synopsis

typedef SLPBoolean SLPAttrCallback(SLPHandle hSLP,
                                   const char* pcAttrList,
                                   SLPError errCode,
                                   void *pvCookie);

4.3.4.2. Description

SLPAttrCallback is the callback type you pass to the SLPFindAttrs() function ๐Ÿฆ‹ How the callback behaves depends on whether you asked for attributes by URL or by service type, so pay attention here, bestie ๐Ÿ‘€

If you called SLPFindAttrs() with a URL, the callback gets called once, no matter whether the handle was opened asynchronously or synchronously. The pcAttrList parameter holds the requested attributes as a comma-separated list. If no attributes matched your original tag list, it's empty ๐Ÿซง

If you called SLPFindAttrs() with a service type, the value of pcAttrList and how often the callback runs depend on whether the handle was opened asynchronously or synchronously. If it was opened asynchronously, the callback gets called every time the API library has results from a remote agent. The pcAttrList parameter MAY be uncollated between calls. Each call has a comma-separated list with the results from whichever agent just returned results ๐ŸŒˆ If the handle was opened synchronously, the results must be collated from all the returning agents, and the callback is called once, with pcAttrList set to the collated result ๐Ÿ‘‘

4.3.4.3. Parameters ๐ŸŽ€

  • hSLP: The SLPHandle used to initiate the operation.
  • pcAttrList: A character buffer containing a comma separated, null terminated list of attribute id/value assignments, in SLP wire format; i.e. "(attr-id=attr-value-list)" [7] ๐Ÿ“
  • errCode: An error code indicating if an error occurred during the operation. The callback should check this error code before processing the parameters. If the error code is other than SLP_OK, then the API library may choose to terminate the outstanding operation. ๐Ÿšจ
  • pvCookie: Memory passed down from the client code that called the original API function, starting the operation. May be NULL. ๐Ÿ“

4.3.4.4. Returns

Okay so the client code should return SLP_TRUE if more data is desired, otherwise SLP_FALSE. Simple as that, bestie ๐Ÿ’…


4.4. Opening and Closing an SLPHandle ๐Ÿฆ‹

4.4.1. SLPOpen

4.4.1.1. Synopsis

   SLPError SLPOpen(const char *pcLang, SLPBoolean isAsync, SLPHandle
   *phSLP);

4.4.1.2. Description

Okay so SLPOpen hands you back a shiny SLPHandle in phSLP for whatever language locale you pass in as pcLang ๐ŸŒธ. You tell it with isAsync whether ops on that handle are synchronous or asynchronous. The handle wraps up the language locale for requests going through it, plus any other resources the implementation needs. BUT SLP properties are NOT wrapped up in the handle, they're global ๐ŸŒ. The function returns an SLPError code for how things went, and if it fails, phSLP comes back NULL ๐Ÿ˜ญ

Now the handle is one-operation-at-a-time only ๐Ÿ™…โ€โ™€๏ธ If the first op was started asynchronously and you try to start another one on that same handle while it's still pending, you get an SLP_HANDLE_IN_USE error back from the API function. SLPClose cancels any outstanding calls on the handle. And if an implementation can't support async (or sync, the other way around) because of memory constraints or no threading support, the SLP_NOT_IMPLEMENTED flag may be returned when isAsync is SLP_TRUE (or SLP_FALSE, respectively) ๐Ÿฅบ

4.4.1.3. Parameters

  • pcLang: A pointer to an array of characters containing the RFC 1766 Language Tag [6] for the natural language locale of requests and registrations issued on the handle. ๐Ÿ—ฃ๏ธ
  • isAsync: An SLPBoolean indicating whether the SLPHandle should be opened for asynchronous operation or not. โณ
  • phSLP: A pointer to an SLPHandle, in which the open SLPHandle is returned. If an error occurs, the value upon return is NULL. ๐Ÿซถ

4.4.2. SLPClose

4.4.2.1. Synopsis

   void SLPClose(SLPHandle hSLP);

4.4.2.2. Description

SLPClose frees all the resources tied to the handle ๐Ÿงน If the handle was invalid, the function just returns silently, no drama ๐Ÿคซ Any outstanding synchronous or asynchronous operations get cancelled, so their callback functions will not be called any further. ๐Ÿ›‘

4.4.2.3. Parameters

  • SLPHandle: A SLPHandle handle returned from a call to SLPOpen(). ๐Ÿ’œ

4.5. Protocol API ๐Ÿ‘‘

4.5.1. SLPReg

4.5.1.1. Synopsis

   SLPError SLPReg(SLPHandle   hSLP,
                   const char  *pcSrvURL,
                   const unsigned short usLifetime,
                   const char  *pcSrvType,
                   const char  *pcAttrs
                   SLPBoolean  fresh,
                   SLPRegReport callback,
                   void *pvCookie);

4.5.1.2. Description

SLPReg registers the URL in pcSrvURL with the lifetime usLifetime and the attribute list in pcAttrs ๐Ÿ“Œ The pcAttrs list is a comma separated list of attribute assignments in wire format (including escaping of reserved characters). The usLifetime parameter must be nonzero and less than or equal to SLP_LIFETIME_MAXIMUM. If fresh is SLP_TRUE, the registration is brand new (the SLP protocol FRESH flag is set) and it replaces any existing registrations. pcSrvType is a service type name, and it can be included for service URLs that are not in the service: scheme. If the URL is in the service: scheme, pcSrvType is ignored. If fresh is SLP_FALSE, then an existing registration gets updated. Rules for new and updated registrations, plus the format for pcAttrs and pcScopeList, can be found in [7]. Registrations and updates take place in the language locale of the hSLP handle. ๐ŸŒˆ

The API library is required to perform the operation in all scopes obtained through configuration. โš™๏ธ

4.5.1.3. Parameters

  • hSLP: The language specific SLPHandle on which to register the advertisement. ๐ŸŽ€
  • pcSrvURL: The URL to register. May not be the empty string. ๐Ÿ”—
  • usLifetime: An unsigned short giving the life time of the service advertisement, in seconds. The value must be an unsigned integer less than or equal to SLP_LIFETIME_MAXIMUM and greater than zero. โฐ
  • pcSrvType: The service type. If pURL is a service: URL, then this parameter is ignored. ๐Ÿงš
  • pcAttrs: A comma separated list of attribute assignment expressions for the attributes of the advertisement. Use empty string, "" for no attributes. ๐Ÿ“
  • fresh: An SLPBoolean that is SLP_TRUE if the registration is new or SLP_FALSE if a reregistration. ๐ŸŒธ
  • callback: A callback to report the operation completion status. ๐Ÿ“ฃ
  • pvCookie: Memory passed to the callback code from the client. May be NULL. ๐Ÿฌ

4.5.1.4. Returns

If an error occurs in starting the operation, one of the SLPError codes is returned. ๐Ÿ™ˆ

4.5.2. SLPDereg

4.5.2.1. Synopsis

   SLPError SLPDereg(SLPHandle  hSLP,
                     const char *pcURL,
                     SLPRegReport callback,
                     void *pvCookie);

4.5.2.2. Description

SLPDereg deregisters the advertisement for URL pcURL in all scopes where the service is registered and in all language locales. The deregistration is not just confined to the locale of the SLPHandle, it's in all locales. Iconic behavior ๐Ÿ‘ The API library is required to perform the operation in all scopes obtained through configuration. ๐Ÿซถ

4.5.2.3. Parameters

  • hSLP: The language specific SLPHandle to use for deregistering. ๐ŸŒ
  • pcURL: The URL to deregister. May not be the empty string. ๐Ÿ”—
  • callback: A callback to report the operation completion status. ๐Ÿ“ฃ
  • pvCookie: Memory passed to the callback code from the client. May be NULL. ๐Ÿฌ

4.5.2.4. Returns

If an error occurs in starting the operation, one of the SLPError codes is returned. ๐Ÿ™ˆ

4.5.3. SLPDelAttrs

4.5.3.1. Synopsis

   SLPError SLPDelAttrs(SLPHandle   hSLP,
                        const char  *pcURL,
                        const char  *pcAttrs,
                        SLPRegReport callback,
                        void *pvCookie);

4.5.3.2. Description

SLPDelAttrs deletes the selected attributes in the locale of the SLPHandle. โœ‚๏ธ The API library is required to perform the operation in all scopes obtained through configuration. ๐ŸŒŸ

4.5.3.3. Parameters

  • hSLP: The language specific SLPHandle to use for deleting attributes. ๐Ÿงฝ
  • pcURL: The URL of the advertisement from which the attributes should be deleted. May not be the empty string. ๐Ÿ”—
  • pcAttrs: A comma separated list of attribute ids for the attributes to deregister. See Section 9.8 in [7] for a description of the list format. May not be the empty string. ๐Ÿ“œ
  • callback: A callback to report the operation completion status. ๐Ÿ“ฃ
  • pvCookie: Memory passed to the callback code from the client. May be NULL. ๐Ÿฌ

4.5.3.4. Returns

If an error occurs in starting the operation, one of the SLPError codes is returned. ๐Ÿ™ˆ

4.5.4. SLPFindSrvTypes

4.5.4.1. Synopsis

   SLPError SLPFindSrvTypes(SLPHandle    hSLP,
                            const char  *pcNamingAuthority,
                            const char  *pcScopeList,
                            SLPSrvTypeCallback callback,
                            void *pvCookie);
Heads up, bestie: the text below says SLPFindSrvType() but the synopsis above says SLPFindSrvTypes. I'm keeping both spellings exactly as the RFC wrote them ๐Ÿ’€

The SLPFindSrvType() function issues an SLP service type request for service types in the scopes indicated by the pcScopeList. ๐Ÿ” The results come back through the callback parameter. The service types are independent of language locale, but only for services registered in one of the scopes and for the indicated naming authority. ๐ŸŒท

If the naming authority is "*", then results come back for all naming authorities. If the naming authority is the empty string, i.e. "", then the default naming authority, "IANA", is used. "IANA" is not a valid naming authority name, and it is a PARAMETER_BAD error to include it explicitly. ๐Ÿ™…โ€โ™€๏ธ

The service type names come back with the naming authority intact. If the naming authority is the default (i.e. empty string), then it's omitted, and so is the separating ".". Service type names from URLs of the service: scheme come back with the "service:" prefix intact. [7] See [8] for more information on the syntax of service type names. ๐Ÿง 

4.5.4.2. Parameters

  • hSLP: The SLPHandle on which to search for types. ๐ŸŽฏ
  • pcNamingAuthority: The naming authority to search. Use "*" for all naming authorities and the empty string, "", for the default naming authority. ๐Ÿ—‚๏ธ
  • pcScopeList: A pointer to a char containing comma separated list of scope names to search for service types. May not be the empty string, "". ๐ŸŒ
  • callback: A callback function through which the results of the operation are reported. ๐Ÿ“ฃ
  • pvCookie: Memory passed to the callback code from the client. May be NULL. ๐Ÿฌ

4.5.4.3. Returns

If an error occurs in starting the operation, one of the SLPError codes is returned. ๐Ÿ™ˆ

4.5.5. SLPFindSrvs

4.5.5.1. Synopsis

   SLPError SLPFindSrvs(SLPHandle  hSLP,
                        const char *pcServiceType,
                        const char *pcScopeList,
                        const char *pcSearchFilter,
                        SLPSrvURLCallback callback,
                        void *pvCookie);

4.5.5.2. Description

Okay so SLPFindSrvs fires off the query for services on the language specific SLPHandle and sends the results back through the callback. The parameters determine the results ๐Ÿฆ‹

4.5.5.3. Parameters

  • hSLP: The language specific SLPHandle on which to search for services. ๐Ÿ”Ž
  • pcServiceType: The Service Type String, including authority string if any, for the request, such as can be discovered using SLPSrvTypes(). This could be, for example "service:printer:lpr" or "service:nfs". May not be the empty string. ๐Ÿ–จ๏ธ
  • pcScopeList: A pointer to a char containing comma separated list of scope names. May not be the empty string, "". ๐ŸŒ
  • pcSearchFilter: A query formulated of attribute pattern matching expressions in the form of a LDAPv3 Search Filter, see [4]. If this filter is empty, i.e. "", all services of the requested type in the specified scopes are returned. โœจ
  • callback: A callback function through which the results of the operation are reported. ๐Ÿ“ฃ
  • pvCookie: Memory passed to the callback code from the client. May be NULL. ๐Ÿฌ

4.5.5.4. Returns

If an error occurs in starting the operation, one of the SLPError codes is returned. ๐Ÿ™ˆ

4.5.6. SLPFindAttrs ๐ŸŒˆ

4.5.6.1. Synopsis

SLPError SLPFindAttrs(SLPHandle   hSLP,
                      const char *pcURLOrServiceType,
                      const char *pcScopeList,
                      const char *pcAttrIds,
                      SLPAttrCallback callback,
                      void *pvCookie);

4.5.6.2. Description

okay so SLPFindAttrs() is the function that gets you the attributes for a service, matched against the attribute ids you ask for โœจ. You give it either a service URL or a service type, and it hands back the attributes through the callback ๐ŸŽ€. If you pass a service URL, you get the attributes for that one particular advertisement, in the language locale of your SLPHandle ๐Ÿ’–.

If you pass a service type (naming authority included, if there is one), you get the attributes for every advertisement of that type, no matter what language they were registered in ๐ŸŒˆ. Again, the results come back through the callback ๐Ÿฆ‹.

You can also filter the results with an SLP attribute request filter string, and the syntax for that lives in [7] ๐Ÿ’…. If the filter string is the empty string, i.e. "", you get all the attributes back, no notes ๐Ÿซถ.

4.5.6.3. Parameters

  • hSLP

The language specific SLPHandle you want to search for attributes on ๐Ÿงš.

  • pcURLOrServiceType

The service URL or the service type. Check [7] for the URL and service type syntax ๐Ÿ’œ. This one MAY NOT be the empty string.

Heads up: "MAY NOT" here is just the plain English way of saying it can't be empty, so it's not a capitalised BCP 14 key word in this version. Don't pass "" ๐Ÿ˜ญ.
  • pcScopeList

A pointer to a char holding a comma separated list of scope names ๐Ÿ“. It may not be the empty string, "".

  • pcAttrIds

The filter string that says which attribute values you want back โœจ. Use the empty string, "", to ask for all of them. Wildcards are also a thing: you can match every attribute id with a particular prefix or suffix ๐ŸŒธ. For the exact format of the filter string, go check [7] ๐Ÿ”ฅ.

  • callback

The callback function where the results of the whole operation get reported ๐Ÿฆ‹.

  • pvCookie

Memory that gets passed from the client over to the callback code. It's allowed to be NULL ๐Ÿ™ˆ.

4.5.6.4. Returns

If something goes wrong while starting the operation, you get back one of the SLPError codes ๐Ÿ’€.

4.6. Miscellaneous Functions

4.6.1. SLPGetRefreshInterval

4.6.1.1. Synopsis

unsigned short SLPGetRefreshInterval();

4.6.1.2. Description

This one returns the biggest min-refresh-interval attribute across all DAs ๐Ÿ‘‘. That number works for the advertised refresh interval bounds of every DA, and if the SA uses it, no refresh registration gets rejected ๐Ÿซถ. If no DA advertises a min-refresh-interval attribute, you get a value of 0 ๐Ÿฅบ.

4.6.1.3. Returns

If there's no error, you get the maximum refresh interval value that all DAs allow (a positive integer) โœจ. If no DA advertises a min-refresh-interval attribute, it returns 0. If an error happens, it returns an SLP error code ๐Ÿ’….

4.6.2. SLPFindScopes

4.6.2.1. Synopsis

SLPError SLPFindScopes(SLPHandle hSLP,
                       char** ppcScopeList);

4.6.2.2. Description

This sets the ppcScopeList parameter to point at a comma separated list with every available scope value in it ๐Ÿ“. The scopes come from a bunch of places: the configuration file's net.slp.useScopes property, unicast to DAs on the net.slp.DAAddresses property, DHCP, or the DA discovery process ๐Ÿงš. If the scopes have any order to them, the preferred ones are listed before the less desirable ones ๐Ÿ’–. There is always at least one name in the list, which is the default scope, "DEFAULT" ๐ŸŒˆ.

4.6.2.3. Parameters

  • hSLP

The SLPHandle you want to search for scopes on ๐Ÿฆ‹.

  • ppcScopeList

A pointer to a char pointer. When the function returns, the buffer pointer gets placed into it ๐Ÿ’œ. The buffer is null terminated. You should free the memory by calling SLPFree() ๐Ÿซถ.

4.6.2.4. Returns

If nothing goes wrong, it returns SLP_OK. Otherwise you get the right error code ๐Ÿ’….

4.6.3. SLPParseSrvURL

4.6.3.1. Synopsis

SLPError SLPParseSrvURL(char *pcSrvURL
                        SLPSrvURL** ppSrvURL);

4.6.3.2. Description

This takes the URL you pass in and parses it into a service URL structure, which it returns through the ppSrvURL pointer ๐Ÿ”ฅ. If a parse error happens, it returns SLP_PARSE_ERROR ๐Ÿ’€. The input buffer pcSrvURL gets destructively modified during the parse, and it's used to fill in the fields of the structure you get back ๐Ÿ™ˆ. You should free that returned structure with SLPFreeURL() ๐ŸŽ€.

If the URL has no service part, the s_pcSrvPart string is the empty string, "", and not NULL ๐ŸŒธ. If pcSrvURL is not a service: URL, then the s_pcSrvType field in the returned structure is the URL's scheme. That might not be the same as the service type it was registered under ๐Ÿ‘€. If the transport is IP, the s_pcTransport field is the empty string ๐Ÿฆ‹. If the transport is not IP, or there's no port number, the s_iPort field is zero ๐Ÿ“.

4.6.3.3. Parameters

  • pcSrvURL

A pointer to a character buffer holding the null terminated URL string you want to parse ๐Ÿงš. It gets destructively modified to produce the output structure.

  • ppSrvURL

A pointer to a pointer for the SLPSrvURL structure that will receive the parsed URL ๐Ÿ’–. Free the memory with a call to SLPFree() once you're done with it ๐Ÿซถ.

4.6.3.4. Returns

If no error occurs, the return value is SLP_OK โœจ. Otherwise, you get the appropriate error code ๐Ÿ’….

4.6.4. SLPEscape

4.6.4.1. Synopsis

SLPError SLPEscape(const char* pcInbuf,
                   char** ppcOutBuf,
                   SLPBoolean isTag);

4.6.4.2. Description

This processes the input string in pcInbuf and escapes any SLP reserved characters ๐ŸŒˆ. If the isTag parameter is SLPTrue, it looks for bad tag characters, and if it finds any, it signals an error by returning the SLP_PARSE_ERROR code ๐Ÿ™ˆ. The results go into a buffer that the API library allocates, and it comes back in the ppcOutBuf parameter ๐ŸŽ€. Deallocate that buffer with SLPFree() once you don't need the memory anymore ๐Ÿ’….

4.6.4.3. Parameters

  • pcInbuf

Pointer to he input buffer to process for escape characters ๐Ÿงš.

  • ppcOutBuf

Pointer to a pointer for the output buffer, with the SLP reserved characters escaped ๐Ÿฆ‹. It must be freed using SLPFree() when the memory isn't needed anymore.

  • isTag

When true, the input buffer is checked for bad tag characters ๐Ÿ“.

4.6.4.4. Returns

It returns SLP_PARSE_ERROR if any characters are bad tag characters and the isTag flag is true ๐Ÿ’€. Otherwise it returns SLP_OK, or the appropriate error code if some other error happens ๐Ÿ’–.

4.6.5. SLPUnescape

4.6.5.1. Synopsis

SLPError SLPUnescape(const char* pcInbuf,
                     char** ppcOutBuf,
                     SLPBoolean isTag);

4.6.5.2. Description

This processes the input string in pcInbuf and unescapes any SLP reserved characters ๐ŸŒธ. If the isTag parameter is SLPTrue, it looks for bad tag characters, and if it finds any, it signals an error with the SLP_PARSE_ERROR code ๐Ÿ‘€. No transformation happens if the input string is an opaque ๐Ÿซถ. The results go into a buffer that the API library allocates, and that comes back in the ppcOutBuf parameter ๐ŸŽ€. Deallocate it with SLPFree() when you don't need it anymore ๐Ÿ’….

4.6.5.3. Parameters

  • pcInbuf

Pointer to he input buffer to process for escape characters ๐Ÿงš.

  • ppcOutBuf

Pointer to a pointer for the output buffer with the SLP reserved characters escaped ๐Ÿฆ‹. It must be freed using SLPFree() when the memory isn't needed anymore.

  • isTag

When true, the input buffer is checked for bad tag characters ๐Ÿ“.

4.6.5.4. Returns

It returns SLP_PARSE_ERROR if any characters are bad tag characters and the isTag flag is true ๐Ÿ’€. Otherwise it returns SLP_OK, or the appropriate error code if another error happens ๐Ÿ’–.

4.6.6. SLPFree

4.6.6.1. Synopsis

void SLPFree(void* pvMem);

4.6.6.2. Description

This frees memory that came back from SLPParseSrvURL(), SLPFindScopes(), SLPEscape(), and SLPUnescape() ๐Ÿงนโœจ.

4.6.6.3. Parameters

  • pvMem

A pointer to the storage allocated by SLPParseSrvURL(), SLPEscape(), SLPUnescape(), or SLPFindScopes() ๐ŸŒˆ. If it's NULL, it gets ignored ๐Ÿ™ˆ.

4.6.7. SLPGetProperty

4.6.7.1. Synopsis

const char* SLPGetProperty(const char* pcName);

4.6.7.2. Description

This returns the value of the matching SLP property name ๐Ÿ’œ. The string that comes back is owned by the library, and you MUST NOT free it ๐Ÿšซ.

4.6.7.3. Parameters

  • pcName

Null terminated string with the property name, from Section 2.1 ๐Ÿฆ‹.

4.6.7.4. Returns

If there's no error, it returns a pointer to a character buffer holding the property value ๐Ÿ’–. If the property wasn't set, you get the default value ๐Ÿซถ. If an error happens, it returns NULL. The returned string MUST NOT be freed ๐Ÿšซ.

4.6.8. SLPSetProperty

4.6.8.1. Synopsis

void SLPSetProperty(const char *pcName,
                    const char *pcValue);

4.6.8.2. Description

This sets the SLP property to the new value ๐ŸŒธ. The pcValue parameter should be the property value as a string โœจ.

4.6.8.3. Parameters

  • pcName

Null terminated string with the property name, from Section 2.1 ๐Ÿงš.

  • pcValue

Null terminated string with the property value, in UTF-8 character encoding ๐Ÿ“.

4.7. Implementation Notes

4.7.1. Refreshing Registrations

okay this one is so good ๐Ÿ˜ญ. Clients say they want URLs to be automatically refreshed by setting the usLifetime parameter in the SLPReg() function call to SLP_LIFETIME_MAXIMUM ๐Ÿ”. That makes the API implementation refresh the URL before it times out ๐Ÿ’–. Yes, using SLP_LIFETIME_MAXIMUM for automatic reregistration means a transient URL can't be registered for the maximum lifetime ๐Ÿ™ˆ. But honestly, little hardship is likely to happen, since service URL lifetimes are measured in seconds, and the client can just use a lifetime of SLP_LIFETIME_MAXIMUM - 1 if it wants a transient URL near the maximum lifetime ๐Ÿซถ. API implementations MUST provide this facility ๐Ÿ‘‘.

4.7.2. Syntax for String Parameters

this section is giving rules, bestie ๐Ÿ’…. Query strings, attribute registration lists, attribute deregistration lists, scope lists, and attribute selection lists all follow the syntax in [7] for the appropriate requests ๐Ÿ“œ. The API directly reflects the strings clients pass in into protocol requests, and it directly reflects the out strings from protocol replies back to clients ๐Ÿฆ‹. So clients are responsible for formatting request strings, including escaping and converting opaque values to escaped byte encoded strings ๐Ÿง . On the way out, clients are required to unescape strings and convert escaped string encoded opaques to binary ๐Ÿซถ. SLPEscape() and SLPUnescape() can help with escaping SLP reserved characters, but they don't do any opaque processing ๐ŸŒธ.

Opaque values are a character buffer holding a UTF-8-encoded string. The first characters are the nonUTF-8 encoding '\ff' ๐Ÿ”ฅ. After that come the escaped values for the original bytes in the opaque ๐ŸŒˆ. The escape convention is pretty simple: an escape is a backslash followed by the two hexadecimal digits that encode the byte ๐ŸŽ€. For example, '\2c' is the byte 0x2c โœจ. Clients handle opaque processing themselves, since the algorithm is relatively simple and uniform ๐Ÿ’œ.

4.7.3. Client Side Syntax Checking ๐Ÿ”

Okay so, client side API implementations are allowed to do syntax checking on scope names, naming authority names, and service type names, but they're not required to ๐Ÿซถ. The C API is basically a thin layer over the protocol, so some low memory SA implementations might find heavy client side checking kinda burdensome ๐Ÿ˜ญ. If syntax checking catches an error in a parameter, the SLP_PARAMETER_BAD error must be returned. And if any parameter is NULL when it's required to be nonNULL, SLP_PARAMETER_BAD gets returned too ๐Ÿ’….

4.7.4. System Properties โš™๏ธ

The system properties set up in the configuration file are reachable through SLPGetProperty() and SLPSetProperty() ๐Ÿ”ง. SLPSetProperty() only changes properties in the running process, not in the configuration file, so it's not a sneaky way to rewrite the config ๐Ÿ™…โ€โ™€๏ธ.

Properties are global to the whole process, so they affect all threads and all handles created with SLPOpen ๐Ÿงต. Errors get checked when a property is actually used and, same as parsing the configuration file, they get logged ๐Ÿ“. The program keeps going without interruption by swapping in the default for the erroneous parameter ๐ŸŒˆ.

With the exception of net.slp.locale, net.slp.typeHint, and net.slp.maxResults, clients of the API should rarely have to override these, since they describe properties of the SLP network that individual agents don't really need to care about ๐Ÿ™ˆ. If changes are required, system administrators should modify the configuration file.

4.7.5. Memory Management ๐Ÿงน

The only API functions that return memory clients actually have to deallocate are SLPParseSrvURL(), SLPFindScopes(), SLPEscape(), and SLPUnescape() ๐Ÿ—‘๏ธ. That memory should be freed with SLPFree() once you're done with it. Character strings returned from SLPGetProperty() should NOT be freed, since they're owned by the SLP library, so hands off ๐Ÿ–๏ธ.

๐Ÿšจ Memory passed to callbacks belongs to the library and MUST NOT be retained by client code. Otherwise, crashes are possible ๐Ÿ’€. Clients are required to copy data out of the callback parameters. No other use of the parameter memory in callback parameters is allowed.

4.7.6. Asynchronous and Incremental Return Semantics ๐Ÿ”

If a handle parameter to an API function was opened asynchronously, the API function call checks the other parameters, opens the appropriate operation, and returns immediately. If an error occurs while starting the operation, an error code is returned โšก. If the handle parameter was opened synchronously, the API function call blocks until all results are available, and it only returns after the results have been reported through the callback function. The return code tells you whether any errors happened both while starting and during the operation ๐Ÿ‘€.

The callback function gets called whenever the API library has results to report ๐Ÿ“ฃ. The callback code is required to check the error code parameter before looking at the other parameters. If the error code is not SLP_OK, the other parameters may be invalid, so be careful bestie ๐Ÿ˜ฌ. The API library has the option of terminating any outstanding operation on which an error occurs. The callback code can similarly indicate that the operation should be terminated by passing back SLP_FALSE.

Callback functions are not permitted to recursively call into the API on the same SLPHandle. If an attempt is made to recursively call into the API, the API function returns SLP_HANDLE_IN_USE ๐Ÿšซ. Why no recursion? Because banning it makes thread safe code way simpler, since locks held on the handle won't be in place during a second outcall on the handle ๐Ÿ”’. The tradeoff is that handle creation should be fairly lightweight, so a client program can easily support multiple outstanding calls ๐Ÿฆ‹.

The total number of results received can be controlled by setting the net.slp.maxResults parameter ๐ŸŽฏ.

On the last call to a callback, whether it's asynchronous or synchronous, the status code passed to the callback has value SLP_LAST_CALL ๐Ÿ. There are four reasons why the call can terminate:

  • DA reply received
    • A reply from a DA has been received and therefore nothing more is expected.
  • Multicast terminated
    • The multicast convergence time has elapsed and the API library multicast code is giving up.
  • Multicast null results
    • Nothing new has been received during multicast for a while and the API library multicast code is giving up on that (as an optimization).
  • Maximum results
    • The user has set the net.slp.maxResults property and that number of replies has been collected and returned.

4.8. Example ๐Ÿ“ฌ

This example illustrates how to discover a mailbox, and it's giving main character energy ๐Ÿ‘‘.

A POP3 server registers itself with the SLP framework. The attributes it registers are "USER", a list of all users whose mail is available through the POP3 server ๐Ÿ’Œ.

The POP3 server code is the following:

SLPHandle slph;
SLPRegReport errCallback = POPRegErrCallback;

/* Create an English SLPHandle, asynchronous processing. */

SLPError err = SLPOpen("en", SLP_TRUE, &slph);

if( err != SLP_OK ) {

  /* Deal with error. */

}

/* Create the service: URL and attribute parameters. */

const char* surl = "service:pop3://mail.netsurf.de"; /* the URL */
const char *pcAttrs = "(user=zaphod,trillian,roger,marvin)"

/* Perform the registration. */

err = SLPReg(slph,
             surl,
             SLP_LIFETIME_DEFAULT,
             ppcAttrs,
             errCallback,
             NULL);

if (err != SLP_OK ) {

   /*Deal with error.*/

}

The errCallback reports any errors ๐Ÿšจ:

void
POPRegErrCallback(SLPHandle hSLP,
                  SLPError errCode,
                  unsigned short usLifetime,
                  void* pvCookie) {

   if( errCode != SLP_OK ) {

     /* Report error through a dialog, message, etc. */

   }

   /*Use lifetime interval to update periodically. */

 }

The POP3 client locates the server for the user with the following code ๐Ÿ”Ž:

/*
 * The client calls SLPOpen(), exactly as above.
 */

const char *pcSrvType   = "service:pop3"; /* the service type  */
const char *pcScopeList = "default";      /* the scope         */
const char *pcFilter    = "(user=roger)"; /* the search filter */
SLPSrvURLCallback srvCallback =           /* the callback      */
                                POPSrvURLCallback;

err = SLPFindSrvs(slph,
                  pcSrvType, pcScopeList, pcFilter,
                  srvCallback, NULL);

if( err != SLP_OK ) {

    /* Deal with error. */

}

Within the callback, the client code can use the returned POP service ๐ŸŽ€:

SLPBoolean
POPSrvURLCallback(SLPHandle hSLP,
                  const char* pcSrvURL,
                  unsigned short sLifetime,
                  SLPError errCode,
                  void* pvCookie) {

   if( errCode != SLP_OK ) {

      /* Deal with error. */

   }

   SLPSrvURL* pSrvURL;

   errCode = SLPParseSrvURL(pcSrvURL, &pSrvURL);

   if (err != SLP_OK ) {

     /* Deal with error. */

   } else {

     /* get the server's address */

     struct hostent *phe = gethostbyname(pSrvURL.s_pcHost);

     /* use hostname in pSrvURL to connect to the POP3 server
      *     . . .
      */

     SLPFreeSrvURL((void*)pSrvURL);  /* Free the pSrvURL storage */
   }

   return SLP_FALSE;                 /* Done! */

}

A client that wanted to discover all the users receiving mail at the server uses the following query ๐Ÿ“ฅ:

/*
 * The client calls SLPOpen(), exactly as above. We assume the
 * service: URL was retrieved into surl.
 */

const char *pcScopeList = "default";      /* the scope            */
const char *pcAttrFilter    = "use";      /* the attribute filter */
SLPAttrCallback attrCallBack =            /* the callback         */
                               POPUsersCallback


err =
  SLPFindAttrs(slph,
               surl,
               pcScopeList, pcAttrFilter,
               attrCallBack, NULL);

if( err != SLP_OK ) {

     /* Deal with error. */

}

The callback processes the attributes ๐Ÿงพ:

SLPBoolean
POPUsersCallback(const char* pcAttrList,
                 SLPError errCode,
                 void* pvCookie) {

  if( errCode != SLP_OK ) {

    /* Deal with error. */

  } else {

    /* Parse attributes. */

  }

  return SLP_FALSE;  /* Done! */

}

5. Java Language Binding โ˜•

5.1. Introduction ๐ŸŒธ

The Java API is designed to model the various SLP entities in classes and objects ๐Ÿงš. APIs are provided for SA, UA, and service type template access capabilities. The ServiceLocationManager class contains methods that return instances of objects implementing SA and UA capability. Each of these is modeled in an interface. The Locator interface provides UA capability and the Advertiser interface provides SA capability. The TemplateRegistry abstract class contains methods that return objects for template introspection and attribute type checking. The ServiceURL, ServiceType, and ServiceLocationAttribute classes model the basic SLP concepts. A concrete subclass instance of TemplateRegistry is returned by a class method โœจ.

All SLP classes and interfaces are located within a single package. The package name should begin with the name of the implementation and conclude with the suffix "slp". Thus, the name for a hypothetical implementation from the University of Michigan would look like:

edu.umich.slp

This follows the Java convention of prepending the top level DNS domain name for the organization implementing the package onto the organization's name and using that as the package prefix ๐ŸŽ“.

5.2. Exceptions and Errors ๐Ÿ™ˆ

Most parameters to API methods are required to be non-null. The API description indicates if a null parameter is acceptable, or if other restrictions constrain a parameter. When parameters are checked for validity (such as not being null) or their syntax is checked, an error results in the RuntimeException subclass IllegalArgumentException being thrown. Clients of the API are reminded that IllegalArgumentException, derived from RuntimeException, is unchecked by the compiler. Clients should thus be careful to include try/catch blocks for it if the relevant parameters could be erroneous ๐Ÿซ .

Standard Java practice is to encode every exceptional condition as a separate subclass of Exception. Because of the relatively high cost in code size of Exception subclasses, the API contains only a single Exception subclass, with different conditions being determined by an integer error code property ๐Ÿงฎ. A subset, appropriate to Java, of the error codes described in Section 3 are available as constants on the ServiceLocationException class. The subset excludes error codes such as MEMORY_ALLOC_FAILED ๐Ÿšซ.

5.2.1. Class ServiceLocationException ๐Ÿ’–

5.2.1.1. Synopsis

public class ServiceLocationException
extends Exception

5.2.1.2. Description

The ServiceLocationException class is thrown by all methods when exceptional conditions occur in the SLP framework ๐Ÿšจ. The error code property determines the exact nature of the condition, and an optional message may provide more information ๐Ÿ’….

5.2.1.3. Fields โœจ

Okay so these are the error codes, bestie, and each one is a static field on the class ๐ŸŽ€ Here they are, all lined up:

   public static final short LANGUAGE_NOT_SUPPORTED = 1
   public static final short PARSE_ERROR = 2
   public static final short INVALID_REGISTRATION = 3
   public static final short SCOPE_NOT_SUPPORTED = 4
   public static final short AUTHENTICATION_ABSENT = 6
   public static final short AUTHENTICATION_FAILED = 7
   public static final short INVALID_UPDATE = 13
   public static final short REFRESH_REJECTED = 15
   public static final short NOT_IMPLEMENTED = 16
   public static final short NETWORK_INIT_FAILED 17
   public static final short NETWORK_TIMED_OUT = 18
   public static final short NETWORK_ERROR = 19
   public static final short INTERNAL_SYSTEM_ERROR = 20
   public static final short TYPE_ERROR = 21
   public static final short BUFFER_OVERFLOW = 22

5.2.1.4. Instance Methods ๐Ÿ’…

Here's the one method you'll reach for, getErrorCode() ๐Ÿฆ‹

   public short getErrorCode()

It just hands back the error code, and that code is always one of the static field values up above. Iconic, honestly ๐Ÿ‘‘

5.3. Basic Data Structures ๐ŸŒธ

5.3.1. Interface ServiceLocationEnumeration ๐Ÿงš

   public interface ServiceLocationEnumeration
    extends Enumeration

5.3.1.1. Description

Okay, so ServiceLocationEnumeration is the return type for every single Locator SLP operation ๐Ÿ’– The Java API library is allowed to make it block until results show up, which means the client can go async by pulling results out of the enumeration on a separate thread. โœจ If a client doesn't care about SLP exceptions, it can just use the superclass nextElement() method instead ๐Ÿ™ˆ

5.3.1.2. Instance Methods

   public abstract Object next() throws ServiceLocationException

This returns the next value, or blocks until one is ready ๐Ÿซถ

Throws:

  • ServiceLocationException: thrown if the SLP operation runs into an error.
  • NoSuchElementException: thrown if there are no more elements to return.

5.3.2. Class ServiceLocationAttribute ๐ŸŽ€

5.3.2.1. Synopsis

   public class ServiceLocationAttribute
     extends Object implements Serializable

5.3.2.2. Description

This class models SLP attributes, and it's giving main character energy ๐Ÿฆ‹ You get instances back from Locator.findAttributes(), and they also travel along with register and deregister requests ๐Ÿ’œ

5.3.2.3. Constructors

   public ServiceLocationAttribute(String id,Vector values)

This builds a service location attribute. Any errors in the id or values vector result in an IllegalArgumentException ๐Ÿ˜ญ

Parameters:

  • id: the attribute name. The String can be made of any Unicode character ๐ŸŒˆ
  • values: a Vector holding one or more attribute values. The contents must all be the same type, and that type has to be one of Integer, String, Boolean, or byte[]. If the attribute is a keyword attribute, the parameter should be null. String values can be made of any Unicode character too ๐Ÿ“

5.3.2.4. Class Methods

   public static String escapeId(String id)

This returns an escaped version of the id parameter, ready to drop into a query โœจ Any reserved characters from [7] get escaped using UTF-8 encoding. If any characters in the tag are illegal, it throws an IllegalArgumentException. ๐Ÿ’€

Parameters:

  • id: the attribute id you want to escape. A ServiceLocationException is thrown if any characters are illegal for an attribute tag.
   public static String escapeValue(Object value)

This returns a String with the escaped value parameter, also ready for a query ๐Ÿซถ If the parameter is a string, any reserved characters from [7] get escaped using UTF-8 encoding. If the parameter is a byte array, the escaped string starts with the nonUTF-8 sequence \ff, and the rest of the string is the escaped bytes, which is the encoding for opaques ๐Ÿ”ฅ If the value parameter is a Boolean or Integer, the returned string is just that object converted into a string. If the value is any type other than String, Integer, Boolean or byte[], you get an IllegalArgumentException ๐Ÿ™…โ€โ™€๏ธ

Parameters:

  • value: the attribute value to be converted into a string and escaped.

5.3.2.5. Instance Methods

   public Vector getValues()

This returns a cloned vector of attribute values, or null if the attribute is a keyword attribute ๐Ÿ’– If the attribute is single-valued, the vector only contains one object.

   public String getId()

This returns the attribute's name ๐ŸŒธ

   public boolean equals(Object o)

This overrides Object.equals(). Two attributes are equal if their identifiers are equal and their value vectors contain the same number of equal values, as judged by the Object equals() method. Byte[] values count as equal if the contents of all the byte arrays in both attribute vectors match. โญ Heads up, though: the SLP string matching algorithm [7] MUST NOT be used for comparing attribute identifiers or string values. That's a hard no ๐Ÿ™…โ€โ™€๏ธ

   public String toString()

This overrides Object.toString(). The string it returns has a formatted representation of the attribute, showing its id, its values, and the Java type of those values ๐Ÿงš It's great for debugging, but it is not in SLP wire format, so don't go sending it over the wire ๐Ÿ˜ญ

   public int hashCode()

This overrides Object.hashCode(), and it hashes on the attribute's identifier ๐Ÿฆ‹

5.3.3. Class ServiceType ๐Ÿ’œ

5.3.3.1. Synopsis

   public class ServiceType extends Object implements Serializable

5.3.3.2. Description

The ServiceType object models the SLP service type ๐ŸŽ€ It takes a string-based service type specifier and breaks it into its components, and then it gives you property accessors to get those components back. URL schemes, protocol service types, and abstract service types are all handled ๐Ÿ‘‘

5.3.3.3. Constructors

   public ServiceType(String type)

This constructs a service type object from the service type specifier. It throws an IllegalArgumentException if the type name is syntactically incorrect ๐Ÿ’€

Parameters:

  • type: the service type name as a String. If the service type comes from a service: URL, the "service:" prefix has to stay intact ๐Ÿซถ

5.3.3.4. Methods

   public boolean isServiceURL()

This returns true if the type name contains the "service:" prefix ๐ŸŒˆ

   public boolean isAbstractType()

This returns true if the type name is for an abstract type ๐Ÿ“

   public boolean isNADefault()

This returns true if the naming authority is the default, i.e. is the empty string โœจ

   public String getConcreteTypeName()

This returns the concrete type name in an abstract type, or the empty string if the service type isn't abstract ๐ŸŒธ For example, if the type name is "service:printing:ipp", the method returns "ipp". If the type name is "service:ftp", the method returns "". ๐Ÿงš

   public String getPrincipleTypeName()

This returns the abstract type name for an abstract type, the protocol name in a protocol type, or the URL scheme for a generic URL ๐Ÿ’– For example, in the abstract type name "service:printing:ipp", the method returns "printing". In the protocol type name "service:ftp", the method returns "ftp". ๐Ÿฆ‹

   public String getAbstractTypeName()

If the type is an abstract type, this returns the fully formatted abstract type name, including the "service:" and the naming authority, but without the concrete type name or the intervening colon ๐Ÿ”ฅ If it isn't an abstract type, it returns the empty string. For example, in the abstract type name "service:printing:ipp", the method returns "service:printing". ๐Ÿ’…

   public String getNamingAuthority()

This returns the naming authority name, or the empty string if the naming authority is the default ๐ŸŽ€

   public boolean equals(Object obj)

This overrides Object.equals(). The two objects are equal if they are both ServiceType objects and all of their components match ๐Ÿซถ

   public String toString()

This returns the fully formatted type name, including the "service:" if the type was originally from a service: URL ๐ŸŒˆ

   public int hashCode()

This overrides Object.hashCode(). It hashes on the string value of the "service" prefix, the naming authority (if any), the abstract and concrete type names for abstract types, the protocol type name for protocol types, and the URL scheme for generic URLs ๐Ÿ’œ

5.3.4. Class ServiceURL ๐Ÿงš

5.3.4.1. Synopsis

   public class ServiceURL extends Object implements Serializable

5.3.4.2. Description

The ServiceURL object models the advertised SLP service URL ๐Ÿฆ‹ It can be either a service: URL or a regular URL. You get these objects back from service lookup requests, and they describe the registered services ๐ŸŒธ This class ought to be a subclass of java.net.URL, but it can't be, because that class is final ๐Ÿ˜ญ

5.3.4.3. Class Variables

   public static final int NO_PORT = 0

This means no port information is required, or none was returned for this URL ๐Ÿ“

   public static final int LIFETIME_NONE = 0

This means the URL has a zero lifetime ๐Ÿ’€ The API never actually returns this value, but you can use it to build a ServiceURL object for deregistering, deleting attributes, or finding attributes โœจ

   public static final int LIFETIME_DEFAULT = 10800

This is the default URL lifetime, which is 3 hours in seconds ๐ŸŒˆ

   public static final int LIFETIME_MAXIMUM = 65535

This is the maximum URL lifetime, which is about 18 hours in seconds ๐Ÿ‘‘

   public static final int LIFETIME_PERMANENT = -1

This means the API implementation should keep re-registering the URL continuously until the application exits ๐Ÿ”ฅ

5.3.4.4. Constructors

   public ServiceURL(String URL,int lifetime)

This constructs a service URL object with the lifetime you specify ๐Ÿ’–

Parameters:

  • URL: the URL as a string. It must be either a service: URL or a valid generic URL according to RFC 2396 [2] ๐Ÿซถ
  • lifetime: the service advertisement lifetime in seconds. This value may be between LIFETIME_NONE and LIFETIME_MAXIMUM ๐ŸŽ€

5.3.4.5. Methods

   public ServiceType getServiceType()

This returns the service type object representing the service type name of the URL ๐Ÿงš

  public final void setServiceType(ServiceType type)
  throws ServiceLocationException

This sets the service type name on the object. It's ignored if the URL is a service: URL ๐Ÿ’…

Parameters:

  • type: the service type object.
   public String getTransport()

This gets the network layer transport identifier. If the transport is IP, an empty string, "", is returned ๐Ÿฆ‹

   public String getHost()

This returns the host identifier. For IP, this is the machine name or IP address ๐ŸŒธ

   public int getPort()

This returns the port number, if there is one. For non-IP transports, it always returns NO_PORT ๐Ÿ“

   public String getURLPath()

This returns the URL path description, if there is one ๐Ÿ’œ

   public int getLifetime()

This returns the service advertisement lifetime. It will be a positive int between LIFETIME_NONE and LIFETIME_MAXIMUM โญ

   public boolean equals(Object obj)

This compares the object to the ServiceURL and returns true if the two are the same. Two ServiceURL objects are equal if their current service types match and they have the same host, port, transport, and URL path ๐Ÿซถ

   public String toString()

This returns a formatted string with the URL, overriding Object.toString(). The returned URL carries the original service type or URL scheme, not the current service type ๐ŸŒˆ

   public int hashCode()

This overrides Object.hashCode(). It hashes on the current service type, transport, host, port, and URL part ๐Ÿงš

5.4. SLP Access Interfaces ๐ŸŽ€

5.4.1. Interface Advertiser ๐Ÿ’–

5.4.1.1. Synopsis

   public interface Advertiser

5.4.1.2. Description ๐Ÿ’…

okay bestie, the Advertiser is the SA interface ๐ŸŽ€ so this is where clients sign up new service instances with SLP, tweak the attributes of services that already exist, and take services off the list when they're done ๐Ÿซถ new registrations and attribute changes happen in the language locale the Advertiser was created with ๐ŸŒธ but deregistrations hit every locale ๐Ÿ’€ no cap, that's a big difference.

5.4.1.3. Instance Methods โœจ

public abstract Locale getLocale()

Returns the language locale this object was created with ๐ŸŒˆ

public abstract void register(ServiceURL URL,
                              Vector attributes)
throws ServiceLocationException

Registers a new service with SLP, using the attributes you hand it ๐Ÿฆ‹

The API library is required to do this in every scope it gets from configuration ๐Ÿ’…

Parameters:

  • URL: the URL for the service.
  • attributes: a vector of ServiceLocationAttribute objects that describe the service.
public abstract void deregister(ServiceURL URL)
throws ServiceLocationException

Takes a service off SLP entirely ๐Ÿ’œ this deregisters it from every language locale, not just one ๐Ÿ˜ญ The API library is required to do this in all scopes obtained through configuration.

Parameters:

  • URL: the URL for the service.
public abstract void
addAttributes(ServiceURL URL,
              Vector attributes)
throws ServiceLocationException

Updates an existing registration by adding new attributes โœจ The API library is required to do this in all scopes obtained through configuration.

Parameters:

  • URL: the URL for the service.
  • attributes: a Vector of ServiceLocationAttribute objects to add to the existing registration. Pass an empty vector if you only want to update the URL on its own. It may not be null ๐Ÿ™ˆ
public abstract void
deleteAttributes(ServiceURL URL,
                 Vector attributeIds)
throws ServiceLocationException

Removes attributes from a URL, but only for the locale the Advertiser was created with ๐Ÿ“ The API library is required to do this in all scopes obtained through configuration.

Parameters:

  • URL: the URL for the service.
  • attributeIds: a vector of Strings naming the ids of the attributes to remove. Each string can be an attribute id or a wildcard pattern that matches ids, and the syntax for those patterns is in [7] ๐Ÿงš The strings can include SLP reserved characters, and the API escapes them before they go over the wire. It may not be the empty vector or null.

5.4.2. Interface Locator ๐Ÿฆ‹

5.4.2.1. Synopsis

public interface Locator

5.4.2.2. Description

the Locator is the UA interface, and it's the one clients use to ask SLP questions ๐Ÿ‘€ what service types exist, which service instances are around, and what attributes an instance or a service type has ๐Ÿ’– queries for services and attributes run in the locale the Locator was created with ๐ŸŒธ queries for service types don't care about locale at all, so they work the same everywhere ๐Ÿซถ

5.4.2.3. Instance Methods ๐Ÿ’…

public abstract Locale getLocale()

Returns the language locale this object was created with ๐ŸŒˆ

public abstract ServiceLocationEnumeration
findServiceTypes(String namingAuthority,
                 Vector scopes)
throws ServiceLocationException

Gives back an enumeration of ServiceType objects for the given scopes and naming authority ๐Ÿ”ฅ If nothing matches, you get an empty enumeration, which is totally fine ๐Ÿ’œ

Parameters:

  • namingAuthority: the naming authority. Use "" for the default naming authority and "*" for all naming authorities.
  • scopes: a Vector of scope names. Pick these from what a findScopes() call gives you. Use "DEFAULT" for the default scope.
public abstract ServiceLocationEnumeration
findServices(ServiceType type,
             Vector scopes,
             String searchFilter)
throws ServiceLocationException

Returns a vector of ServiceURL objects for services that match the query and have a matching type in the given scopes โœจ If nothing is found, you get an empty enumeration ๐Ÿงš

Parameters:

  • type: the SLP service type of the service.
  • scopes: a Vector of scope names. Pick these from what a findScopes() call gives you. Use "DEFAULT" for the default scope.
  • searchFilter: an LDAPv3 [4] string encoded query. If the filter is empty, meaning "", every service of the requested type in the specified scopes comes back ๐Ÿ“ SLP reserved characters must be escaped in the query. Use ServiceLocationAttribute.escapeId() and ServiceLocationAttribute.escapeValue() to build the query.
public abstract ServiceLocationEnumeration
findAttributes(ServiceURL URL,
               Vector scopes,
               Vector attributeIds)
throws ServiceLocationException

For the URL and scope, you get back a Vector of ServiceLocationAttribute objects whose ids match the String patterns in attributeIds ๐Ÿฆ‹ The request goes out in the Locator's locale ๐ŸŒธ If no attributes match, you get an empty enumeration.

Parameters:

  • URL: the URL you want the attributes for.
  • scopes: a Vector of scope names. Pick these from what a findScopes() call gives you. Use "DEFAULT" for the default scope.
  • attributeIds: a Vector of String patterns that identify the attributes you want. An empty vector means return all attributes ๐Ÿ’… As described in [7], the patterns can use wildcards to match substrings. The strings can include SLP reserved characters, and the API escapes them before transmission.
public abstract ServiceLocationEnumeration
findAttributes(ServiceType type,
               Vector scopes,
               Vector attributeIds)
throws ServiceLocationException

For the type and scope, you get back a Vector of every ServiceLocationAttribute object whose ids match the String patterns in attributeIds, no matter what the Locator's locale is ๐Ÿ‘‘ The request ignores language locale completely ๐ŸŒˆ If no attributes are found, you get an empty vector.

Parameters:

  • serviceType: the service type.
  • scopes: a Vector of scope names. Pick these from what a findScopes() call gives you. Use "DEFAULT" for the default scope.
  • attributeIds: a Vector of String patterns that identify the attributes you want. An empty vector means return all attributes. As described in [7], the patterns can use wildcards to match all prefixes or suffixes. The patterns can include SLP reserved characters, and the API escapes them before transmission ๐Ÿ’–

5.5. The Service Location Manager ๐ŸŒˆ

5.5.1. Class ServiceLocationManager

5.5.1.1. Synopsis

public class ServiceLocationManager
extends Object

5.5.1.2. Description

the ServiceLocationManager is the gatekeeper for the whole service location framework ๐Ÿงš clients get their Locator and Advertiser objects (for UA and SA) from it, and they get the Vector of known scope names from it too ๐Ÿ’…

5.5.1.3. Class Methods ๐Ÿ”ฅ

public static int getRefreshInterval()
throws ServiceLocationException

Returns the maximum min-refresh-interval attribute value across all DAs ๐Ÿ‘€ That value satisfies the advertised refresh interval bounds for every DA, and if the SA uses it, no refresh registration will get rejected ๐Ÿซถ If no DA advertises a min-refresh-interval attribute, you get back 0.

public static Vector findScopes()
throws ServiceLocationException

Returns a Vector of strings with every available scope name ๐ŸŒธ The list pulls from a bunch of different sources, and Section 2.1 has the scope discovery algorithm if you want the details ๐Ÿฆ‹ There is always at least one string in the Vector, and that's the default scope, "DEFAULT" โœจ

public static Locator
getLocator(Locale locale)
throws ServiceLocationException

Returns a Locator object for the given language Locale ๐Ÿ’œ If the implementation doesn't support UA functionality, it returns null ๐Ÿ˜ญ

Parameters:

  • locale: the language locale of the Locator. The default SLP locale is used if this is null.
public static Advertiser
getAdvertiser(Locale locale)
throws ServiceLocationException

Returns an Advertiser object for the given language locale ๐Ÿ“ If the implementation doesn't support SA functionality, it returns null.

Parameters:

  • locale: the language locale of the Advertiser. The default SLP locale is used if this is null.

5.6. Service Template Introspection ๐Ÿงš

5.6.1. Abstract Class TemplateRegistry

5.6.1.1. Synopsis

public abstract class TemplateRegistry

5.6.1.2. Description

Subclasses of the TemplateRegistry abstract class give you access to service location templates [8] ๐ŸŽ€ TemplateRegistry classes do a few jobs ๐Ÿ’… they manage how service type template documents get registered and accessed, and they build attribute verifiers out of service templates so you can verify attributes and introspect template documents ๐Ÿ”ฅ Heads up, though: clients of the Advertiser don't have to verify attributes before registering ๐Ÿ™ˆ (you might still get a TYPE_ERROR if the implementation supports type checking and something doesn't match the template) ๐ŸŒˆ

5.6.1.3. Class Methods ๐Ÿ‘‘

public static TemplateRegistry getTemplateRegistry();

Returns the distinguished TemplateRegistry object for doing operations on and with service templates ๐Ÿ’– If the implementation doesn't support TemplateRegistry functionality, it returns null ๐Ÿฅบ

5.6.1.4. Instance Methods โœจ

Okay bestie, here are the instance methods on the template registry, and they're the main event ๐Ÿ’…

public abstract void
registerServiceTemplate(ServiceType type,
                        String documentURL,
                        Locale locale,
                        String version)
throws ServiceLocationException

This one registers the service template with the template registry ๐ŸŽ€

  • type: the service type.
  • documentURL: a String with the URL of the template document. It may not be the empty string ๐Ÿ™ˆ
  • locale: a Locale object with the language locale of the template ๐ŸŒธ
  • version: the version number identifier of the template document ๐Ÿ”ฅ
public abstract void
deregisterServiceTemplate(ServiceType type,
                          Locale locale,
                          String version)
throws ServiceLocationException

This one deregisters the template for the service type ๐Ÿฆ‹

  • type: the service type.
  • locale: a Locale object with the language locale of the template.
  • version: a String with the version number. Pass null to mean the latest version ๐Ÿ“
public abstract
String findTemplateURL(ServiceType type,
                       Locale locale,
                       String version)
throws ServiceLocationException

This one returns the URL for the template document ๐Ÿงš

  • type: the service type.
  • locale: a Locale object with the language locale of the template.
  • version: a String with the version number. Pass null to mean the latest version โœจ
public abstract
ServiceLocationAttributeVerifier
attributeVerifier(String documentURL)
throws ServiceLocationException

This one reads the template document URL and hands back an attribute verifier for the service type. Main character energy ๐Ÿ‘‘ The verifier can be used to check that registration attributes match the template, and to introspect on the template definition ๐Ÿ’œ

  • documentURL: a String with the template document's URL. It may not be the empty string.

5.6.2. Interface ServiceLocationAttributeVerifier ๐Ÿฆ‹

5.6.2.1. Synopsis

public interface ServiceLocationAttributeVerifier

5.6.2.2. Description

Okay so the ServiceLocationAttributeVerifier is basically your access pass to service templates ๐ŸŽ€ Classes that implement it parse SLP template definitions, give you info on attribute definitions for service types, and check whether a ServiceLocationAttribute object matches a template for a particular service type. Clients get their ServiceLocationAttributeVerifier objects for specific SLP service types through the TemplateRegistry ๐Ÿ’…

5.6.2.3. Instance Methods

public abstract ServiceType getServiceType()

Returns the SLP service type this verifier is for ๐ŸŒˆ

public abstract Locale getLocale()

Returns the language locale of the template ๐ŸŒธ

public abstract String getVersion()

Returns the template version number identifier ๐Ÿ”ฅ

public abstract String getURLSyntax()

Returns the URL syntax expression for the service: URL ๐Ÿ“

public abstract String getDescription()

Returns the descriptive help text for the template ๐Ÿ’œ

public abstract ServiceLocationAttributeDescriptor
getAttributeDescriptor(String attrId)

Returns the ServiceLocationAttributeDescriptor for the attribute with the given id. If there's no such attribute in this template, it returns null. This one is mostly for GUI tools that want to show attribute info ๐Ÿงš If you're checking attributes in code, use the verifyAttribute() method instead, bestie ๐Ÿซถ

public abstract Enumeration
getAttributeDescriptors()

Returns an Enumeration that lets you introspect on the attribute definitions in the service template. It hands back ServiceLocationAttributeDescriptor objects for the attributes โœจ Same deal as above: this is mostly for GUI tools to display attribute info, and programmatic checks should use verifyAttribute() ๐Ÿ‘‘

public abstract void
verifyAttribute(
  ServiceLocationAttribute attribute)
throws ServiceLocationException

Verifies that the attribute matches the template definition. If it doesn't match, a ServiceLocationException is thrown with the error code ServiceLocationException.PARSE_ERROR ๐Ÿ˜ญ

  • attribute: the ServiceLocationAttribute object to be verified.
public abstract void
verifyRegistration(
  Vector attributeVector)
throws ServiceLocationException

Verifies that the Vector of ServiceLocationAttribute objects matches the template for this service type ๐ŸŽ€ The vector MUST contain all the required attributes, and all attributes MUST match their template definitions. If the attributes don't match, a ServiceLocationException is thrown with the error code ServiceLocationException.PARSE_ERROR ๐Ÿ™ˆ

  • attributeVector: a Vector of ServiceLocationAttribute objects for the registration.
Heads up: the vector has to hit every required attribute. Missing one is a no-go, no cap ๐Ÿ’€

5.6.3. Interface ServiceLocationAttributeDescriptor ๐Ÿงš

5.6.3.1. Synopsis

public interface
ServiceLocationAttributeDescriptor

5.6.3.2. Description

This interface gives you introspection on a template attribute definition ๐Ÿฆ‹ Classes that implement ServiceLocationAttributeDescriptor return info about one particular service location attribute definition from the service template. It's mostly for GUI tools ๐ŸŒธ For programmatic attribute verification, you should go through the ServiceLocationAttributeVerifier instead ๐Ÿ’…

5.6.3.3. Instance Methods

public abstract String getId()

Returns a String with the attribute's id ๐Ÿ“

public abstract String getValueType()

Returns a String with the fully package-qualified Java type of the attribute. SLP types get translated into Java types like this:

  • STRING: "java.lang.String"
  • INTEGER: "java.lang.Integer"
  • BOOLEAN: "java.lang.Boolean"
  • OPAQUE: "[B" (i.e. array of byte, byte[])
  • KEYWORD: empty string, ""
public abstract String getDescription()

Returns a String with the attribute's help text ๐Ÿ”ฅ

public abstract Enumeration
getAllowedValues()

Returns an Enumeration of the allowed values for the attribute type. For keyword attributes it returns null. For no allowed values (i.e. unrestricted) it returns an empty Enumeration ๐ŸŒˆ

public abstract Enumeration
getDefaultValues()

Returns an Enumeration of the default values for the attribute type. For keyword attributes it returns null. For no allowed values (i.e. unrestricted) it returns an empty Enumeration โœจ

public abstract boolean
getRequiresExplicitMatch()

Returns true if the "X"" flag is set. That means the attribute should be included in any Locator.findServices() request search filter ๐Ÿ‘‘

public abstract boolean getIsMultivalued()

Returns true if the "M" flag is set ๐Ÿ’œ

public abstract boolean getIsOptional()

Returns true if the "O"" flag is set ๐Ÿงš

public abstract boolean getIsLiteral()

Returns true if the "L" flag is set ๐ŸŽ€

public abstract boolean getIsKeyword()

Returns true if the attribute is a keyword attribute ๐ŸŒธ

5.7. Implementation Notes ๐Ÿ’–

5.7.1. Refreshing Registrations

There's a special lifetime constant, ServiceURL.LIFETIME_PERMANENT, that clients use to say the URL should get automatically refreshed until the application exits ๐Ÿ”ฅ The API implementation should read this as meaning the URL lifetime is ServiceURL.LIFETIME_MAXIMUM, and it MUST arrange for automatic refresh to happen ๐Ÿซถ

5.7.2. Parsing Alternate Transports in ServiceURL

The ServiceURL class is built to handle multiple transports ๐Ÿฆ‹ The standard API does no extra processing on transports other than IP, except to split out the host identifier and the URL path. Implementations are free to subclass ServiceURL and add methods for more detailed parsing of alternate transport info ๐ŸŒˆ For IP transport, the port number (if there is one) comes back from the getPort() method. For non-IP transports, getPort() returns NO_PORT ๐Ÿ“

5.7.3. String Attribute Values

Generally, translating Java types for attribute values into the SLP on-the-wire string is pretty straightforward ๐Ÿ’… But there are two corner cases, and they're lowkey tricky ๐Ÿ™ˆ If the Java attribute value type is String and the string has an on-the-wire representation that SLP infers as an integer, the registered value might not be what the API client meant ๐Ÿ˜ญ A similar problem happens if the Java attribute value is the string "true" or "false", because then the on-the-wire representation gets inferred as boolean. To handle these, the Java API adds a space to the front of the string. So if the string attribute value is "123", the Java API changes it to "123 ", and SLP infers that as a string โœจ Since leading and trailing spaces have no effect on query handling, this shouldn't cause any problems with queries ๐Ÿ‘‘ API clients do need to know the transformation is happening, though ๐Ÿซถ

5.7.4. Client Side Syntax Checking

The syntax of scope names, service type names, naming authority names, and URLs is described in [7] and [8] ๐Ÿ“š The various methods and classes that take String parameters for these entities SHOULD type check the parameters for syntax errors on the client side, and throw an IllegalArgumentException if there's an error ๐Ÿ’œ Also, character escaping SHOULD be implemented before network transmission for escapable characters in attribute ids and String values ๐ŸŒธ This cuts down on the number of error messages sent over the wire ๐Ÿ”ฅ The ServiceLocationAttribute class has methods that let clients grab escaped attribute id and value strings to make query construction easier ๐Ÿงš

5.7.5. Language Locale Handling

The Locator and Advertiser interfaces are created with a Locale parameter ๐ŸŒˆ The language locale they're created with gets used in all SLP requests issued through that object. If the Locale parameter is null, the default SLP locale is used ๐ŸŽ€ To find the default SLP locale, it first checks the net.slp.locale System property ๐Ÿ’… If that's unset, the default SLP locale [7] is used, which is "en" ๐Ÿ“ Heads up: the default SLP locale might not be the same as the default Java locale ๐Ÿ‘‘

5.7.6. Setting SLP System Properties โœจ

okay so SLP system properties that get set in the configuration file can be overridden inside API clients, and it's honestly so easy ๐Ÿ’… You just call System.getProperties() to grab a copy of the system properties, then modify or add the SLP property you want, and finally use System.setProperties() to set things to that modified Property object. Program execution keeps going without interruption, and if a parameter is erroneous, the default gets substituted in its place ๐Ÿซถ Errors are checked when the property is actually used, and they get logged.

bestie, the SLP configuration file can't be read with the java.util.Properties file reader ๐Ÿ™ˆ The reason is that there are some syntactic differences. The SLP configuration file defines a different escape convention for non-ASCII characters than the Java syntax does. Once the file has been read, though, the properties get stored and retrieved from java.util.Properties objects, so it all works out in the end ๐ŸŒˆ

Properties are global for a process, which means they affect all threads and all Locator and Advertiser objects obtained through the ServiceLocationManager ๐ŸŒธ With the exception of the net.slp.locale, net.slp.typeHint, and net.slp.maxResults properties, clients should rarely need to override these, since they reflect properties of the SLP network that aren't really the concern of individual agents. If changes are required, system administrators should modify the configuration file. That's the vibe โœจ

5.7.7. Multithreading ๐Ÿฆ‹

Thread-safe operation is relatively easy to achieve in Java, and it's giving very doable energy ๐Ÿ’– By making each method in the classes that implement the Locator and Advertiser interfaces synchronized, and by synchronizing access to any shared data structures within the class, the Locator and Advertiser interfaces are made safe. Alternatively, finer grained synchronization is also possible within the classes implementing Advertiser and Locator, if you're feeling extra ๐Ÿ’…

5.7.8. Modular Implementations ๐Ÿงš

ngl, at first glance the API may look rather heavyweight ๐Ÿ’€ But the design has been carefully arranged so that modular implementations are possible. You can have implementations that provide only SA, only UA, or only service template access capability, or any combination of the three. Iconic, right? ๐Ÿ‘‘

Because the objects returned from ServiceLocationManager.getLocator() and ServiceLocationManager.getAdvertiser() are interfaces, and because the objects returned through those interfaces are in the set of base data structures, an implementation is free to omit either UA or SA capability. It does this by simply returning null from the instance creation operation if the classes implementing the missing function cannot be dynamically linked. API clients are encouraged to check for this contingency and to signal an exception if it occurs ๐ŸŽ€ Similarly, the TemplateRegistry concrete subclass can simply be omitted from an implementation that only supports UA and/or SA clients, and the TemplateRegistry.getRegistry() method can return null. That way, the API implementation can be tailored for the particular memory requirements at hand ๐Ÿ“

In addition, if an implementation only supports the minimal subset of SLP [7], the unsupported Locator and Advertiser interface operations can throw an exception with ServiceLocationException.NOT_IMPLEMENTED as the error code. This supports better source portability between low and high memory platforms, which is such a clean move ๐Ÿซถ

5.7.9. Asynchronous and Incremental Return Semantics โญ

The Java API contains no specific support for asynchronous operation, bestie ๐Ÿ™ˆ Incremental return isn't needed for the Advertiser, because service registrations can be broken up into pieces when they're large. Asynchronous return isn't needed either, because clients can always issue the Advertiser operation in a separate thread if the calling thread can't block.

The Locator can be implemented either synchronously or asynchronously. Since the return type for Locator calls is ServiceLocationEnumeration, a Java API implementation that supports asynchronous semantics can implement ServiceLocationEnumeration to dole results out as they come in, blocking when no results are available. If the client code needs to support other processing while the results are trickling in, the call into the enumeration to retrieve the results can be done in a separate thread ๐Ÿฆ‹

Unlike the C case, collation semantics for return of attributes, when an attribute request by service type is made, require that the API collate returned values. This means only one attribute, having a collation of all returned values, appears to the API client. In practice, this may limit the amount of asynchronous processing possible with the findAttributes() method ๐Ÿ˜ญ This requirement is imposed because memory management is much easier in Java, so implementing collation as part of the API shouldn't be as difficult as in C. It also saves the client from having to do the collation itself, which is a whole mood ๐Ÿ’œ

5.8. Example ๐ŸŒˆ

In this example, a printer server advertises its availability to clients. Additionally, the server advertises a service template for use by client software in validating service requests. Let's gooo ๐Ÿ”ฅ

  //Get the Advertiser and TemplateRegistry.

  Advertiser adv = null;
  TemplateRegistry tr = null

  try {

    adv = ServiceLocationManager.getAdvertiser("en");

    tr = TemplateRegistry.getTemplateRegistry();

  } catch( ServiceLocationException ex ) { } //Deal with error.

  if( adv == null ) {

    //Serious error as printer can't be registered
    //  if the implementation doesn't support SA
    //  functionality.

  }

  //Get the printer's attributes, from a file or
  //  otherwise. We assume that the attributes
  //  conform to the template, otherwise, we
  //  could register the template here and verify
  //  them.

  Vector attributes = getPrinterAttributes();

  //Create the service: URL for the printer.

  ServiceURL printerURL =
    new ServiceURL(
      "service:printer:lpr://printshop/color2",
      ServiceURL.LIFETIME_MAXIMUM);

  try {

    //Register the printer.

    adv.register(printerURL, attributes);
    //If the template registry is available,
    //  register the printer's template.

    if( tr != null ) {
      tr.registerServiceTemplate(
        new ServiceType("service:printer:lpr"),
        "http://shop.arv/printer/printer-lpr.slp",
        new Locale("en",""),
        "1.0");

   }

  } catch( ServiceLocationException ex ) { } //Deal with error.

Suppose a client is looking for a color printer. The following code is used to issue a request for printer advertisements ๐Ÿ–จ๏ธ๐Ÿ’–

  Locator loc = null;
  TemplateRegistry tr = null;

  try {

    loc = ServiceLocationManager.getLocator("en");

  } catch( ServiceLocationException ex ) { } //Deal with error.

  if( loc == null ) {

    //Serious error as client can't be located
    //  if the implementation doesn't support
    //  UA functionality.

  }

  //We want a color printer that does CMYK
  //  and prints at least 600 dpi.

  String query = "(&(marker-type=CMYK)(resolution=600))";

  //Get scopes.

  Vector scopes = ServiceLocationManager.findScopes();

  Enumeration services;

  try {

    services =
      loc.findServices(new ServiceType("service:printer"),scopes,query);

  } catch { } //Deal with error.

  if (services.hasMoreElements() ) {

    //Printers can now be used.
    ServiceURL surl = (ServiceURL) services.next();

    Socket sock = new Socket(surl.getHost, surl.getPort());

    // Use the Socket...

  }

6. Internationalization Considerations ๐ŸŒ

6.1. service URL ๐Ÿ”—

The service URL itself must be encoded using the rules set forth in [2]. The character set encoding is limited to specific ranges within the UTF-8 character set [3].

The attribute information associated with the service URL must be expressed in UTF-8. See [8] for attribute internationalization guidelines ๐Ÿ’…

6.2. Character Set Encoding ๐Ÿ”ค

Configuration and serialized registration files are encoded in the UTF-8 character set [3]. This is fully compatible with US-ASCII character values. C platforms that do not support UTF-8 are required to check the top bit of input bytes to determine whether the incoming character is multibyte. If it is, the character should be dealt with accordingly. This should require no additional implementation effort, since the SLP wire protocol requires that strings are encoded as UTF-8. C platforms without UTF-8 support need to supply their own support, if only in the form of multibyte string handling ๐Ÿซถ

At the API level, the character encoding is specified to be Unicode for Java and UTF-8 for C. Unicode is the default in Java. For C, the standard US-ASCII 8 bits per character, null terminated C strings are a subset of the UTF-8 character set, and so work in the API. Because the C API is very simple, the API library needs to do a minimum of processing on UTF-8 strings. The strings primarily just need to be reflected into the outgoing SLP messages, and reflected out of the API from incoming SLP messages โœจ

6.3. Language Tagging ๐Ÿณ๏ธโ€๐ŸŒˆ

All SLP requests and registrations are tagged to indicate in which language the strings included are encoded. This allows multiple languages to be supported. It also presents the possibility that error conditions result when a request is made in a language that is not supported. In this case, an error is only returned when there is data available, but not obtainable in the language requested.

The dialect portion of the Language Tag is used on a 'best effort' basis for matching strings by SLP. Dialects that match are preferred over those which don't. Dialects that do not match will not prevent string matching or comparisons from occurring ๐Ÿฆ‹

7. Security Considerations ๐Ÿ”

Security is handled within the API library and is not exposed to API clients except in the form of exceptions. The net.slp.securityEnabled property determines whether an SA client's messages are signed, but a UA client should be prepared for an authentication exception at any time, because it may contact a DA with authenticated advertisements.

An adversary could delete valid service advertisements, provide false service information, and deny UAs knowledge of existing services unless the mechanisms in SLP for authenticating SLP messages are used. These mechanisms allow DAAdverts, SAAdverts, Service URLs and Service Attributes to be verified using digital cryptography. For this reason, all SLP agents should be configured to use SLP SPIs. See [7] for a description of how this mechanism works. This part is seriously important, bestie, so please don't skip it ๐Ÿ’€๐Ÿ”ฅ

8. Acknowledgements ๐Ÿ’œ

The authors would like to thank Don Provan for his pioneering work during the initial stages of API definition ๐Ÿ‘‘

9. References ๐Ÿ“š

  • [1] Bradner, S., "Key Words for Use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
  • [2] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
  • [3] Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC 2279, January 1998.
  • [4] Howes, T., "The String Representation of LDAP Search Filters", RFC 2254 December 1997.
  • [5] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.
  • [6] Alvestrand, H., "Tags for the Identification of Languages", RFC 1766, March 1995.
  • [7] Guttman, E., Perkins, C., Veizades, J. and M. Day, "Service Location Protocol, Version 2", RFC 2608, June 1999.
  • [8] Guttman, E., Perkins, C. and J. Kempf, "Service Templates and Service: Schemes", RFC 2609, June 1999.

10. Authors' Addresses โœจ

okay bestie, if you have questions about this memo, these are the two people to ask ๐Ÿ’–

James Kempf ๐ŸŽ€ Sun Microsystems 901 San Antonio Rd. Palo Alto, CA, 94303 USA

Phone: +1 650 786 5890 Fax: +1 650 786 6445 EMail: james.kempf@sun.com


Erik Guttman ๐Ÿฆ‹ Sun Microsystems Bahnstr. 2 74915 Waibstadt Germany

Phone: +49 7263 911 701 EMail: erik.guttman@sun.com

Copyright (C) The Internet Society (1999). All Rights Reserved. ๐ŸŒธ

okay so this document and translations of it can be copied and shared with others ๐Ÿซถ and people can write derivative works that comment on it, explain it, or help people implement it. they can be prepared, copied, published, and distributed, in whole or in part, without restriction of any kind, as long as the above copyright notice and this paragraph are included on all of those copies and derivative works โœจ

BUT, and this is important bestie ๐Ÿ™ˆ, this document itself may not be modified in any way. that means you can't remove the copyright notice or the references to the Internet Society or other Internet organizations. the exceptions are when it's needed for developing Internet standards, in which case the copyright procedures in the Internet Standards process must be followed, or when it's needed to translate it into languages other than English ๐ŸŒˆ

the limited permissions above are perpetual, meaning they will never be revoked by the Internet Society or its successors or assigns ๐Ÿ’œ

and the whole document and the information in it is provided on an "AS IS" basis. THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT USING THE INFORMATION WILL NOT INFRINGE ANY RIGHTS, AND ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. no cap, that's a lot of legal energy ๐Ÿ˜ญ

Acknowledgement ๐Ÿ“

Funding for the RFC Editor function is currently provided by the Internet Society. ๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from