/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2001 by Sun Microsystems, Inc.
* All rights reserved.
*
*/
// SLPHeaderV2.java: Base class for Service Location Messages
// Author: James Kempf
// Created On: Thu Oct 9 08:50:31 1997
// Last Modified By: James Kempf
// Last Modified On: Wed Jan 6 15:24:26 1999
// Update Count: 472
//
/**
* The SLPHeaderV2 class serves as the header class for all SLPv2 messages.
* It contains instance variables for SLP message header contents,
* and implements the SLPHeaderV2 interface.
*
* @author James Kempf
*/
// Support for options.
// Maximum message size (24 bits).
// Location of flag byte.
// Various header flags.
// Header sizes. Note that this doesn't include the language tag,
// which is variable.
protected static final int HEADER_BYTES =
// Maximum protected scopes allowed.
// Registered option classes.
// Manditory option range.
// Sizes of option id and extension fields (in bytes).
// Interfaces for options to use.
interface OptionParser {
// Parse the option from the data stream. We include the header also,
// in case it is needed.
throws ServiceLocationException, IOException;
}
interface SLPOption {
// Externalize the option to the byte array stream. We include the
// header also, in case it is needed.
throws ServiceLocationException;
}
// Register an option parsing class.
// We should probably check if it implements SLPOption.OptionParser,
// but...
}
//
// Header instance variables.
//
// For the incoming message side.
SLPHeaderV2() {
super();
}
// Initialize the new SLPHeaderV2 from the input stream. Version and
// function code have already been removed from the stream.
throws ServiceLocationException, IOException {
this.functionCode = functionCode;
// Get length.
// Get flags.
byte[] b = new byte[2];
nbytes += 2;
// We could check for null on reserved part of flags field, but
// in the spirit of "be liberal in what you receive" we don't.
// Get option offset.
// Check option offset for sanity.
throw
"option_error",
new Object[] {
}
// Get transaction id.
// Get language code.
// Everything went OK coming in, so set the error code.
}
// By default, the header parses the client side message. A server
// side subclass must replace this. We do this so that the amount of code
// in the client is minimized, since this class must be in both.
throws ServiceLocationException,
// Get the error code, if not SAAdvert.
}
// Switch and convert according to function code.
switch (functionCode) {
case SrvLocHeader.SrvRply:
break;
case SrvLocHeader.AttrRply:
break;
case SrvLocHeader.SrvTypeRply:
break;
case SrvLocHeader.DAAdvert:
break;
case SrvLocHeader.SrvAck:
// We act as a SrvAck.
rply = this;
iNumReplies = 1;
break;
case SrvLocHeader.SAAdvert:
break;
default:
throw
"function_code_error",
new Object[] {
new Integer(functionCode)});
}
// Check for size overflow.
throw
"length_overflow",
new Object[] {
}
return rply;
}
// Construct a header for output. Used by the client side code to
// construct an initial request and the server side code to construct
// a reply.
throws ServiceLocationException {
// Check for proper function code and nonnull locale.
(functionCode >= SrvReq)),
"function_code_error",
"null_locale_error",
new Object[0]);
this.functionCode = functionCode;
// If there's not enough for the error code (if any), then signal
// an error. The assumption here is that the message is going
// via UDP or multicast.
byte[] ltag =
if (payLen < SHORT_SIZE) {
throw
"buffer_overflow",
new Object[] {
new Integer(packetLength)});
}
}
// Externalize the message by converting it to bytes and writing
// it to the output stream.
public void
throws ServiceLocationException {
// Convert the locale to a tag. We need the length.
byte[] ltagBytes =
// Set the multicast flag.
// We need to get stuff into another stream first, so we can correctly
// calculate the length.
// Need to put in the error code. There will only be an error code
// if error codes are applicable for this message type. Note
// that room for the error code was reserved in the initial
// calculation of the header, so there should always be room
// for it, even if the packet overflowed otherwise.
}
// Put in the previous responders, if there are any. Note that
// there may be only when the error code is not put out.
// We check against the packet size during parsing so that
// we don't overflow the packet and throw a special exception
// if an overflow happens. We only put out the previous
// responders list if the request is going by multicast, but
// we need to put out an empty vector for unicast requests.
int prevResLen =
}
// If the error code is OK, then insert the rest of the message
// and parse the options. If there was an error,
// this step is skipped because the data isn't relevant.
// Externalize any options.
}
// Set the length here to the actual length of the packet.
// If we exceed the 24 bit length size, we are hosed.
if (length > MAX_MESSAGE_LENGTH) {
throw
"max_msg_size_exceeded",
new Object[0]);
}
// Truncate if necessary. We will always have room for a header
// and error code because we check when creating the object.
// Note that no URL block will be truncated because the spec
// says it can't be.
overflow = true;
byte[] newBytes = new byte[packetLength];
}
//
// Write out the header.
//
// Write version and function code.
// Put length in.
// Put in flags.
if (overflow) {
} else {
}
if (fresh) {
} else {
}
if (mcast) {
} else {
}
// Write out flags.
//
// Write the body.
//
}
//
// Option handling.
//
// Parse any options.
throws ServiceLocationException,
// If no options return.
if (optOff == 0) {
return;
}
int optNext = 0;
// Parse any options in the data stream.
do {
// Parse extension id.
// Parse extension offset.
// Lookup an option parser.
// May be an exception if class is null.
// In mandatory range. Throw an exception.
if ((optId >= MANDATORY_OPTION_LOW) &&
(optId <= MANDATORY_OPTION_HIGH)) {
throw
"v2_unsup_option",
}
// Skip the rest of the option.
if (optNext != 0) {
}
} else {
try {
// Parse the option.
// Insert option into option table.
} catch (InstantiationException ex) {
throw
"v2_option_inst",
} catch (IllegalAccessException ex) {
throw
"v2_option_sec",
}
}
} while (optNext != 0);
}
// Externalize any options.
throws ServiceLocationException {
// Calculate offset to options, if any.
int toOpt = 0;
return toOpt;
}
// For all options in the table, parse them out.
while (en.hasMoreElements()) {
// Linearize option object.
// Calculate offset to next options.
// Plop it into the output stream.
// Check whether there are more options first. If so, then
// the next offset is zero.
if (en.hasMoreElements()) {
} else {
}
}
return toOpt;
}
// Parse the previous responder list out, being sure to truncate
// so the list is syntactically correct if there is an overflow.
// This duplicates the comma separated list code to a certain
// extent.
private void
int available)
throws ServiceLocationException {
for (i = 0; i < n; i++) {
// Add comma if necessary.
if (i > 0) {
}
// Convert to UTF8 bytes.
// Write bytes to stream if there's room.
} else {
// Throw exception, upper layers need to break off multicast.
// This exception should *never* be surfaced.
throw
"v2_prev_resp_overflow",
new Object[] {});
}
}
// Now write to the real stream.
}
//
// Utilities for parsing service URL's and attribute lists, with
// authentication information.
//
// Parse in a service URL including lifetime if necessary.
short err)
throws ServiceLocationException, IOException {
// Ignore reserved byte.
byte[] b = new byte[1];
nbytes += 1;
// Get URL lifetime.
// Get URL.
// Get auth block, if any.
// Get number of auth blocks.
b = new byte[1];
nbytes += 1;
if (nauths > 0) {
}
try {
} catch (IllegalArgumentException ex) {
throw
"malformed_url",
}
// Put it in the auth block for this URL.
}
return url;
}
// Parse out a service URL, create authentication blocks if necessary.
// Return true if the URL was output. Check that we don't overflow
// packet size in the middle.
boolean
boolean urlAuth,
boolean checkOverflow)
throws ServiceLocationException {
// We need to keep track of size, so we don't overflow packet length.
// Convert the URL to bytes.
// Parse out reserved.
nbytes += 1;
// Parse out the lifetime.
byte bs = (byte)0;
// Process auth block list if required.
if (urlAuth) {
// Create an auth block if necessary.
}
}
// Put out the URL bytes.
// Write auth block size.
nbytes += 1;
// If there are auth blocks required, put them out now.
if (bs > (byte)0) {
}
// If we can, write it out.
return true; // nbytes already set...
} else {
return false;
}
}
// Parse in a potentially authenticated attribute list.
boolean allowMultiValuedBooleans)
throws ServiceLocationException, IOException {
// First, parse in the attribute vector.
byte[] rawBytes =
// Get the attribute list signature, if necessary.
}
// Parse in a list of attributes into attrs, returing raw bytes.
// ServiceLocationAttribute objects. Clients take care of auth blocks.
byte[]
boolean allowMultiValuedBooleans)
throws ServiceLocationException, IOException {
// Parse the list into ServiceLocationAttribute objects.
for (i = 0; i < n; i++) {
}
return rawBytes;
}
// Parse out a vector of ServiceLocationAttributes. Includes escaping
// characters.
byte[]
int lifetime,
boolean attrAuth,
boolean writeAuthCount)
throws ServiceLocationException {
int nBlocks = 0;
// Convert attribute vector to comma separated list.
// Convert the attributes to strings, escaping characters to
// escape.
while (en.hasMoreElements()) {
}
// Create the comma separated list.
if (attrAuth) {
}
} else {
}
// Get number of blocks if authentication.
}
// Write out the bytes.
// Write out number of auth blocks.
if (writeAuthCount) {
nbytes += 1;
}
// Write out the attribute authentication blocks.
}
return bytes;
}
// Get an auth block list, checking first for security.
throws ServiceLocationException {
throw
"auth_classes_missing",
new Object[0]);
}
}
// Get an SLPAuthBlockList, checking first if security is enabled.
byte nauth,
throws ServiceLocationException, IOException {
throw
"auth_classes_missing",
new Object[0]);
}
}
// Parse in an attribute signature.
throws ServiceLocationException, IOException {
byte[] b = new byte[1];
nbytes += 1;
if (nauths > 0) {
}
return auth;
}
//
// Utility functions to help with verification of data.
//
// Escape tags, check for strings. Trim trailing, leading whitespace,
// since it is ignored for matching purposes and tags are only
// used for matching.
throws ServiceLocationException {
int i, n = t.size();
for (i = 0; i < n; i++) {
if (o instanceof String) {
// Escape tag.
false);
} else {
throw
new Object[0]));
}
}
}
// Unescape tags. Trim trailing and leading whitespace since it is
// ignored for matching purposes and tags are only used for matching.
throws ServiceLocationException {
int i, n = t.size();
for (i = 0; i < n; i++) {
tag =
}
}
// Escape vector of scope strings.
throws ServiceLocationException {
for (i = 0; i < n; i++) {
i);
}
}
// Unescape vector of scope strings.
throws ServiceLocationException {
for (i = 0; i < n; i++) {
i);
}
}
// Error if somebody tries to do this client side.
long timestamp,
throws ServiceLocationException {
"v2_daadvert_client_side",
new Object[0]);
return null; // never get here...
}
// Reimplement clone() to get the header size right.
throws CloneNotSupportedException {
return hdr;
}
}