package com.sun.slp;
import java.util.*;
import java.net.*;
import java.io.*;
class SLPHeaderV2 extends SrvLocHeader implements Cloneable {
private int optOff = 0;
Hashtable optTable = new Hashtable();
private final static int MAX_MESSAGE_LENGTH = 0xffffff;
static final int FLAG_BYTE = 4;
protected static final int NOFLAG = 0x00;
static final int OVERFLOW = 0x80;
protected static final int FRESH = 0x40;
protected static final int MCAST = 0x20;
protected static final int REST_HEADER_BYTES = 12;
protected static final int HEADER_BYTES =
VERSION_FUNCTION_BYTES + REST_HEADER_BYTES;
protected static final int MAX_PROTECTED_SCOPES = 255;
protected static Hashtable optClasses = new Hashtable();
protected static int MANDATORY_OPTION_LOW = 0x4000;
protected static int MANDATORY_OPTION_HIGH = 0x7fff;
protected static int OPT_ID_SIZE = 2;
protected static int OPT_OFF_SIZE = 2;
interface OptionParser {
abstract SLPOption parse(SLPHeaderV2 hdr, DataInputStream dsr)
throws ServiceLocationException, IOException;
}
interface SLPOption {
abstract void externalize(SLPHeaderV2 hdr, ByteArrayOutputStream baos)
throws ServiceLocationException;
}
static void registerOptionClass(int id, Class optClass) {
Integer key = Integer.valueOf(id);
optClasses.put(key, optClass);
}
SLPHeaderV2() {
super();
version = Defaults.version;
}
void parseHeader(int functionCode, DataInputStream dis)
throws ServiceLocationException, IOException {
this.functionCode = functionCode;
nbytes += 2;
length = getInt24(dis);
byte[] b = new byte[2];
dis.readFully(b, 0, 2);
nbytes += 2;
byte flags = (byte) ((char)b[0] & 0xFF);
overflow = ((flags & OVERFLOW) != NOFLAG);
fresh = ((flags & FRESH) != NOFLAG);
mcast = ((flags & MCAST) != NOFLAG);
optOff = getInt24(dis);
if (optOff > length) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"option_error",
new Object[] {
Integer.valueOf(optOff), Integer.valueOf(length)});
}
xid = (short)getInt(dis);
StringBuffer buf = new StringBuffer();
getString(buf, dis);
locale = SLPConfig.langTagToLocale(buf.toString());
errCode = ServiceLocationException.OK;
}
SrvLocMsg parseMsg(DataInputStream dis)
throws ServiceLocationException,
IOException,
IllegalArgumentException {
SrvLocMsg rply = null;
if (functionCode != SrvLocHeader.SAAdvert) {
errCode = (short)getInt(dis);
}
switch (functionCode) {
case SrvLocHeader.SrvRply:
rply = new CSrvMsg(this, dis);
break;
case SrvLocHeader.AttrRply:
rply = new CAttrMsg(this, dis);
break;
case SrvLocHeader.SrvTypeRply:
rply = new CSrvTypeMsg(this, dis);
break;
case SrvLocHeader.DAAdvert:
rply = new CDAAdvert(this, dis);
break;
case SrvLocHeader.SrvAck:
rply = this;
iNumReplies = 1;
break;
case SrvLocHeader.SAAdvert:
rply = new CSAAdvert(this, dis);
break;
default:
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"function_code_error",
new Object[] {
Integer.valueOf(functionCode)});
}
if (nbytes > length) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"length_overflow",
new Object[] {
Integer.valueOf(nbytes), Integer.valueOf(length)});
}
return rply;
}
SLPHeaderV2(int functionCode, boolean fresh, Locale locale)
throws ServiceLocationException {
Assert.slpassert(((functionCode <= SAAdvert) &&
(functionCode >= SrvReq)),
"function_code_error",
new Object[] {Integer.valueOf(functionCode)});
Assert.slpassert((locale != null),
"null_locale_error",
new Object[0]);
this.version = Defaults.version;
this.functionCode = functionCode;
this.locale = locale;
this.xid = getUniqueXID();
this.fresh = fresh;
byte[] ltag =
getStringBytes(SLPConfig.localeToLangTag(locale), Defaults.UTF8);
int headerLen = ltag.length + HEADER_BYTES;
int payLen = packetLength - headerLen;
if (payLen < SHORT_SIZE) {
throw
new ServiceLocationException(
ServiceLocationException.BUFFER_OVERFLOW,
"buffer_overflow",
new Object[] {
Integer.valueOf(headerLen + SHORT_SIZE),
Integer.valueOf(packetLength)});
}
}
public void
externalize(ByteArrayOutputStream baos, boolean mcast, boolean isTCP)
throws ServiceLocationException {
byte[] ltagBytes =
getStringBytes(SLPConfig.localeToLangTag(locale), Defaults.UTF8);
int ltagLen = ltagBytes.length;
this.mcast = mcast;
ByteArrayOutputStream bbaos = new ByteArrayOutputStream();
if (functionCode == SrvLocHeader.SrvAck ||
functionCode == SrvLocHeader.SrvTypeRply ||
functionCode == SrvLocHeader.SrvRply ||
functionCode == SrvLocHeader.AttrRply ||
functionCode == SrvLocHeader.DAAdvert) {
putInt(errCode, bbaos);
}
int prevResLen =
packetLength - (payload.length + HEADER_BYTES + ltagLen);
Vector resp = previousResponders;
if (resp != null) {
resp = (mcast ? resp:new Vector());
parsePreviousRespondersOut(resp, bbaos, prevResLen);
}
if (errCode == ServiceLocationException.OK) {
bbaos.write(payload, 0, payload.length);
optOff = externalizeOptions(bbaos, ltagLen);
}
byte[] payloadBytes = bbaos.toByteArray();
length = HEADER_BYTES + ltagLen + payloadBytes.length;
if (length > MAX_MESSAGE_LENGTH) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"max_msg_size_exceeded",
new Object[0]);
}
if (!isTCP && (length > packetLength)) {
overflow = true;
length = packetLength;
byte[] newBytes = new byte[packetLength];
System.arraycopy(payloadBytes, 0, newBytes, 0,
length - (HEADER_BYTES + ltagLen));
payloadBytes = newBytes;
}
baos.write((byte) (0xFF & version));
baos.write((byte) (0xFF & functionCode));
putInt24(length, baos);
byte flags = (byte)NOFLAG;
if (overflow) {
flags = (byte)(flags | OVERFLOW);
} else {
flags = (byte)(flags & ~OVERFLOW);
}
if (fresh) {
flags = (byte)((flags | FRESH) & 0xFF);
} else {
flags = (byte)((flags & ~FRESH) & 0xFF);
}
if (mcast) {
flags = (byte)((flags | MCAST) & 0xFF);
} else {
flags = (byte)((flags & ~MCAST) & 0xFF);
}
baos.write((byte) (0xFF & flags));
baos.write((byte)0);
putInt24(optOff, baos);
putInt(xid, baos);
putInt(ltagLen, baos);
baos.write(ltagBytes, 0, ltagBytes.length);
baos.write(payloadBytes, 0, payloadBytes.length);
}
void parseOptions(DataInputStream dsr)
throws ServiceLocationException,
IOException,
IllegalArgumentException {
if (optOff == 0) {
return;
}
int optNext = 0;
do {
int optId = getInt(dsr);
optNext = getInt(dsr);
Integer key = Integer.valueOf(optId);
Class optClass = (Class)optClasses.get(key);
if (optClass == null) {
if ((optId >= MANDATORY_OPTION_LOW) &&
(optId <= MANDATORY_OPTION_HIGH)) {
throw
new ServiceLocationException(
ServiceLocationException.OPTION_NOT_SUPPORTED,
"v2_unsup_option",
new Object[] {key});
}
int skipStart = length;
if (optNext != 0) {
skipStart = optNext;
}
dsr.skipBytes(skipStart - nbytes);
} else {
try {
OptionParser optParser =
(OptionParser)optClass.newInstance();
SLPOption opt = optParser.parse(this, dsr);
optTable.put(key, opt);
} catch (InstantiationException ex) {
throw
new ServiceLocationException(
ServiceLocationException.INTERNAL_SYSTEM_ERROR,
"v2_option_inst",
new Object[] {key, ex});
} catch (IllegalAccessException ex) {
throw
new ServiceLocationException(
ServiceLocationException.INTERNAL_SYSTEM_ERROR,
"v2_option_sec",
new Object[] {key, ex});
}
}
} while (optNext != 0);
}
private int externalizeOptions(ByteArrayOutputStream baos, int langTagLen)
throws ServiceLocationException {
int toOpt = 0;
if (optTable.size() <= 0) {
return toOpt;
}
toOpt = HEADER_BYTES + langTagLen + baos.size();
Enumeration en = optTable.keys();
int nextOpt = toOpt;
while (en.hasMoreElements()) {
Integer id = (Integer)en.nextElement();
SLPOption opt = (SLPOption)optTable.get(id);
ByteArrayOutputStream obaos = new ByteArrayOutputStream();
opt.externalize(this, obaos);
nextOpt += obaos.size() + OPT_ID_SIZE + OPT_OFF_SIZE;
putInt(id.intValue(), baos);
if (en.hasMoreElements()) {
putInt(nextOpt, baos);
} else {
putInt(0, baos);
}
byte[] bytes = obaos.toByteArray();
baos.write(bytes, 0, bytes.length);
}
return toOpt;
}
private void
parsePreviousRespondersOut(Vector resp,
ByteArrayOutputStream baos,
int available)
throws ServiceLocationException {
ByteArrayOutputStream bbaos = new ByteArrayOutputStream();
int i, n = resp.size();
for (i = 0; i < n; i++) {
String address = (String)resp.elementAt(i);
if (i > 0) {
address = "," + address;
}
byte[] bytes = getStringBytes(address, Defaults.UTF8);
if (bytes.length <= available) {
bbaos.write(bytes, 0, bytes.length);
available = available - bytes.length;
} else {
throw
new ServiceLocationException(
ServiceLocationException.PREVIOUS_RESPONDER_OVERFLOW,
"v2_prev_resp_overflow",
new Object[] {});
}
}
byte[] out = bbaos.toByteArray();
putInt(out.length, baos);
baos.write(out, 0, out.length);
nbytes += out.length;
}
ServiceURL
parseServiceURLIn(DataInputStream dis,
Hashtable authTable,
short err)
throws ServiceLocationException, IOException {
byte[] b = new byte[1];
dis.readFully(b, 0, 1);
nbytes += 1;
int lifetime = getInt(dis);
StringBuffer buf = new StringBuffer();
byte[] rawBytes = getString(buf, dis);
Hashtable auth = null;
b = new byte[1];
dis.readFully(b, 0, 1);
nbytes += 1;
byte nauths = (byte)(b[0] & 0xFF);
if (nauths > 0) {
ByteArrayOutputStream abaos = new ByteArrayOutputStream();
putInteger(rawBytes.length, abaos);
Object[] message = new Object[2];
message[0] = abaos.toByteArray();
message[1] = rawBytes;
auth = getCheckedAuthBlockList(message, nauths, dis);
lifetime = AuthBlock.getShortestLifetime(auth);
}
String ssurl = buf.toString();
ServiceURL url = null;
try {
url = new ServiceURL(ssurl, lifetime);
} catch (IllegalArgumentException ex) {
throw
new ServiceLocationException(err,
"malformed_url",
new Object[] {ex.getMessage()});
}
if (auth != null) {
authTable.put(url, auth);
}
return url;
}
boolean
parseServiceURLOut(ServiceURL surl,
boolean urlAuth,
Hashtable auth,
ByteArrayOutputStream baos,
boolean checkOverflow)
throws ServiceLocationException {
ByteArrayOutputStream bbaos = new ByteArrayOutputStream();
int mbytes = nbytes;
byte[] bytes = getStringBytes(surl.toString(), Defaults.UTF8);
bbaos.write((byte)(0xFF & 0));
nbytes += 1;
putInt(surl.getLifetime(), bbaos);
byte bs = (byte)0;
if (urlAuth) {
if (auth == null) {
ByteArrayOutputStream abaos = new ByteArrayOutputStream();
putInteger(bytes.length, abaos);
Object[] message = new Object[2];
message[0] = abaos.toByteArray();
message[1] = bytes;
auth = getCheckedAuthBlockList(message, surl.getLifetime());
}
bs = (byte) auth.size();
Object[] bytesArray = AuthBlock.getContents(auth);
bytes = (byte[]) bytesArray[1];
}
putInt(bytes.length, bbaos);
bbaos.write(bytes, 0, bytes.length);
nbytes += bytes.length;
bbaos.write((byte)(0xFF & bs));
nbytes += 1;
if (bs > (byte)0) {
AuthBlock.externalizeAll(this, auth, bbaos);
}
bytes = bbaos.toByteArray();
if (!checkOverflow || nbytes <= packetLength) {
baos.write(bytes, 0, bytes.length);
return true;
} else {
nbytes = mbytes;
return false;
}
}
Hashtable
parseAuthenticatedAttributeVectorIn(Vector attrs,
DataInputStream dis,
boolean allowMultiValuedBooleans)
throws ServiceLocationException, IOException {
byte[] rawBytes =
parseAttributeVectorIn(attrs, dis, allowMultiValuedBooleans);
ByteArrayOutputStream abaos = new ByteArrayOutputStream();
putInteger(rawBytes.length, abaos);
Object[] message = new Object[2];
message[0] = abaos.toByteArray();
message[1] = rawBytes;
return parseSignatureIn(message, dis);
}
byte[]
parseAttributeVectorIn(Vector attrs,
DataInputStream dis,
boolean allowMultiValuedBooleans)
throws ServiceLocationException, IOException {
StringBuffer buf = new StringBuffer();
byte[] rawBytes = getString(buf, dis);
Vector attrForms = parseCommaSeparatedListIn(buf.toString(), false);
int i, n = attrForms.size();
for (i = 0; i < n; i++) {
String attrForm =
(String)attrForms.elementAt(i);
attrs.addElement(
new ServiceLocationAttribute(
attrForm, allowMultiValuedBooleans));
}
return rawBytes;
}
byte[]
parseAttributeVectorOut(Vector v,
int lifetime,
boolean attrAuth,
Hashtable auth,
ByteArrayOutputStream baos,
boolean writeAuthCount)
throws ServiceLocationException {
byte[] bytes = null;
int nBlocks = 0;
if (!attrAuth || auth == null) {
Vector strings = new Vector();
Enumeration en = v.elements();
while (en.hasMoreElements()) {
ServiceLocationAttribute attr =
(ServiceLocationAttribute)en.nextElement();
strings.addElement(attr.externalize());
}
String clist = vectorToCommaSeparatedList(strings);
bytes = getStringBytes(clist, Defaults.UTF8);
if (attrAuth) {
ByteArrayOutputStream abaos = new ByteArrayOutputStream();
putInteger(bytes.length, abaos);
Object[] message = new Object[2];
message[0] = abaos.toByteArray();
message[1] = bytes;
auth = getCheckedAuthBlockList(message, lifetime);
}
} else {
Object[] bytesArray = AuthBlock.getContents(auth);
bytes = (byte[]) bytesArray[1];
}
if (auth != null) {
nBlocks = auth.size();
}
putInt(bytes.length, baos);
baos.write(bytes, 0, bytes.length);
nbytes += bytes.length;
if (writeAuthCount) {
baos.write((byte)(nBlocks & 0xFF));
nbytes += 1;
}
if (attrAuth && nBlocks > 0) {
AuthBlock.externalizeAll(this, auth, baos);
}
return bytes;
}
Hashtable getCheckedAuthBlockList(Object[] message, int lifetime)
throws ServiceLocationException {
if (!SLPConfig.getSLPConfig().getHasSecurity()) {
throw
new ServiceLocationException(
ServiceLocationException.AUTHENTICATION_ABSENT,
"auth_classes_missing",
new Object[0]);
}
return AuthBlock.makeAuthBlocks(message, lifetime);
}
Hashtable getCheckedAuthBlockList(Object[] message,
byte nauth,
DataInputStream dis)
throws ServiceLocationException, IOException {
if (!SLPConfig.getSLPConfig().getHasSecurity()) {
throw
new ServiceLocationException(
ServiceLocationException.AUTHENTICATION_ABSENT,
"auth_classes_missing",
new Object[0]);
}
return AuthBlock.makeAuthBlocks(this, message, dis, nauth);
}
Hashtable parseSignatureIn(Object[] message, DataInputStream dis)
throws ServiceLocationException, IOException {
Hashtable auth = null;
byte[] b = new byte[1];
dis.readFully(b, 0, 1);
nbytes += 1;
byte nauths = (byte)(b[0] & 0xFF);
if (nauths > 0) {
auth = getCheckedAuthBlockList(message, nauths, dis);
}
return auth;
}
void escapeTags(Vector t)
throws ServiceLocationException {
int i, n = t.size();
for (i = 0; i < n; i++) {
Object o = t.elementAt(i);
if (o instanceof String) {
String tag =
ServiceLocationAttribute.escapeAttributeString((String)o,
false);
t.setElementAt(tag.trim(), i);
} else {
throw
new IllegalArgumentException(
SLPConfig.getSLPConfig().formatMessage("nonstring_tag",
new Object[0]));
}
}
}
void unescapeTags(Vector t)
throws ServiceLocationException {
int i, n = t.size();
for (i = 0; i < n; i++) {
String tag = (String)t.elementAt(i);
tag =
ServiceLocationAttribute.unescapeAttributeString(tag, false);
t.setElementAt(tag.trim(), i);
}
}
static void escapeScopeStrings(Vector scopes)
throws ServiceLocationException {
int i, n = scopes.size();
Vector ret = new Vector();
for (i = 0; i < n; i++) {
String scope = (String)scopes.elementAt(i);
scopes.setElementAt(
ServiceLocationAttribute.escapeAttributeString(scope, false),
i);
}
}
static void unescapeScopeStrings(Vector scopes)
throws ServiceLocationException {
int i, n = scopes.size();
Vector ret = new Vector();
for (i = 0; i < n; i++) {
String scope = (String)scopes.elementAt(i);
scopes.setElementAt(
ServiceLocationAttribute.unescapeAttributeString(scope, false),
i);
}
}
SDAAdvert
getDAAdvert(short xid,
long timestamp,
ServiceURL url,
Vector scopes,
Vector attrs)
throws ServiceLocationException {
Assert.slpassert(false,
"v2_daadvert_client_side",
new Object[0]);
return null;
}
public Object clone()
throws CloneNotSupportedException {
SLPHeaderV2 hdr = (SLPHeaderV2)super.clone();
byte[] langBytes = getStringBytes(locale.toString(),
Defaults.UTF8);
hdr.nbytes = HEADER_BYTES + langBytes.length + 2;
return hdr;
}
}