10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7298SMark.J.Nelson@Sun.COM * Common Development and Distribution License (the "License"). 6*7298SMark.J.Nelson@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 220Sstevel@tonic-gate * Copyright (c) 2001 by Sun Microsystems, Inc. 230Sstevel@tonic-gate * All rights reserved. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate // SLPHeaderV2.java: Base class for Service Location Messages 280Sstevel@tonic-gate // Author: James Kempf 290Sstevel@tonic-gate // Created On: Thu Oct 9 08:50:31 1997 300Sstevel@tonic-gate // Last Modified By: James Kempf 310Sstevel@tonic-gate // Last Modified On: Wed Jan 6 15:24:26 1999 320Sstevel@tonic-gate // Update Count: 472 330Sstevel@tonic-gate // 340Sstevel@tonic-gate 350Sstevel@tonic-gate package com.sun.slp; 360Sstevel@tonic-gate 370Sstevel@tonic-gate import java.util.*; 380Sstevel@tonic-gate 390Sstevel@tonic-gate import java.net.*; 400Sstevel@tonic-gate import java.io.*; 410Sstevel@tonic-gate 420Sstevel@tonic-gate /** 430Sstevel@tonic-gate * The SLPHeaderV2 class serves as the header class for all SLPv2 messages. 440Sstevel@tonic-gate * It contains instance variables for SLP message header contents, 450Sstevel@tonic-gate * and implements the SLPHeaderV2 interface. 460Sstevel@tonic-gate * 470Sstevel@tonic-gate * @author James Kempf 480Sstevel@tonic-gate */ 490Sstevel@tonic-gate 500Sstevel@tonic-gate class SLPHeaderV2 extends SrvLocHeader implements Cloneable { 510Sstevel@tonic-gate 520Sstevel@tonic-gate // Support for options. 530Sstevel@tonic-gate 540Sstevel@tonic-gate private int optOff = 0; 550Sstevel@tonic-gate Hashtable optTable = new Hashtable(); 560Sstevel@tonic-gate 570Sstevel@tonic-gate // Maximum message size (24 bits). 580Sstevel@tonic-gate 590Sstevel@tonic-gate private final static int MAX_MESSAGE_LENGTH = 0xffffff; 600Sstevel@tonic-gate 610Sstevel@tonic-gate // Location of flag byte. 620Sstevel@tonic-gate 630Sstevel@tonic-gate static final int FLAG_BYTE = 4; 640Sstevel@tonic-gate 650Sstevel@tonic-gate // Various header flags. 660Sstevel@tonic-gate 670Sstevel@tonic-gate protected static final int NOFLAG = 0x00; 680Sstevel@tonic-gate static final int OVERFLOW = 0x80; // needed by Transact. 690Sstevel@tonic-gate protected static final int FRESH = 0x40; 700Sstevel@tonic-gate protected static final int MCAST = 0x20; 710Sstevel@tonic-gate 720Sstevel@tonic-gate // Header sizes. Note that this doesn't include the language tag, 730Sstevel@tonic-gate // which is variable. 740Sstevel@tonic-gate 750Sstevel@tonic-gate protected static final int REST_HEADER_BYTES = 12; 760Sstevel@tonic-gate protected static final int HEADER_BYTES = 770Sstevel@tonic-gate VERSION_FUNCTION_BYTES + REST_HEADER_BYTES; 780Sstevel@tonic-gate 790Sstevel@tonic-gate // Maximum protected scopes allowed. 800Sstevel@tonic-gate 810Sstevel@tonic-gate protected static final int MAX_PROTECTED_SCOPES = 255; 820Sstevel@tonic-gate 830Sstevel@tonic-gate // Registered option classes. 840Sstevel@tonic-gate 850Sstevel@tonic-gate protected static Hashtable optClasses = new Hashtable(); 860Sstevel@tonic-gate 870Sstevel@tonic-gate // Manditory option range. 880Sstevel@tonic-gate 890Sstevel@tonic-gate protected static int MANDATORY_OPTION_LOW = 0x4000; 900Sstevel@tonic-gate protected static int MANDATORY_OPTION_HIGH = 0x7fff; 910Sstevel@tonic-gate 920Sstevel@tonic-gate // Sizes of option id and extension fields (in bytes). 930Sstevel@tonic-gate 940Sstevel@tonic-gate protected static int OPT_ID_SIZE = 2; 950Sstevel@tonic-gate protected static int OPT_OFF_SIZE = 2; 960Sstevel@tonic-gate 970Sstevel@tonic-gate // Interfaces for options to use. 980Sstevel@tonic-gate 990Sstevel@tonic-gate interface OptionParser { 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate // Parse the option from the data stream. We include the header also, 1020Sstevel@tonic-gate // in case it is needed. 1030Sstevel@tonic-gate parse(SLPHeaderV2 hdr, DataInputStream dsr)1040Sstevel@tonic-gate abstract SLPOption parse(SLPHeaderV2 hdr, DataInputStream dsr) 1050Sstevel@tonic-gate throws ServiceLocationException, IOException; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate interface SLPOption { 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate // Externalize the option to the byte array stream. We include the 1120Sstevel@tonic-gate // header also, in case it is needed. 1130Sstevel@tonic-gate externalize(SLPHeaderV2 hdr, ByteArrayOutputStream baos)1140Sstevel@tonic-gate abstract void externalize(SLPHeaderV2 hdr, ByteArrayOutputStream baos) 1150Sstevel@tonic-gate throws ServiceLocationException; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate // Register an option parsing class. 1200Sstevel@tonic-gate registerOptionClass(int id, Class optClass)1210Sstevel@tonic-gate static void registerOptionClass(int id, Class optClass) { 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate Integer key = new Integer(id); 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate // We should probably check if it implements SLPOption.OptionParser, 1260Sstevel@tonic-gate // but... 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate optClasses.put(key, optClass); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate // 1330Sstevel@tonic-gate // Header instance variables. 1340Sstevel@tonic-gate // 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate // For the incoming message side. 1370Sstevel@tonic-gate SLPHeaderV2()1380Sstevel@tonic-gate SLPHeaderV2() { 1390Sstevel@tonic-gate super(); 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate version = Defaults.version; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate // Initialize the new SLPHeaderV2 from the input stream. Version and 1460Sstevel@tonic-gate // function code have already been removed from the stream. 1470Sstevel@tonic-gate parseHeader(int functionCode, DataInputStream dis)1480Sstevel@tonic-gate void parseHeader(int functionCode, DataInputStream dis) 1490Sstevel@tonic-gate throws ServiceLocationException, IOException { 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate this.functionCode = functionCode; 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate nbytes += 2; // for version and function code... 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate // Get length. 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate length = getInt24(dis); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate // Get flags. 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate byte[] b = new byte[2]; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate dis.readFully(b, 0, 2); 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate nbytes += 2; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate byte flags = (byte) ((char)b[0] & 0xFF); 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate overflow = ((flags & OVERFLOW) != NOFLAG); 1700Sstevel@tonic-gate fresh = ((flags & FRESH) != NOFLAG); 1710Sstevel@tonic-gate mcast = ((flags & MCAST) != NOFLAG); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate // We could check for null on reserved part of flags field, but 1740Sstevel@tonic-gate // in the spirit of "be liberal in what you receive" we don't. 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate // Get option offset. 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate optOff = getInt24(dis); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate // Check option offset for sanity. 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate if (optOff > length) { 1830Sstevel@tonic-gate throw 1840Sstevel@tonic-gate new ServiceLocationException( 1850Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 1860Sstevel@tonic-gate "option_error", 1870Sstevel@tonic-gate new Object[] { 1880Sstevel@tonic-gate new Integer(optOff), new Integer(length)}); 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate // Get transaction id. 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate xid = (short)getInt(dis); 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate // Get language code. 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate StringBuffer buf = new StringBuffer(); 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate getString(buf, dis); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate locale = SLPConfig.langTagToLocale(buf.toString()); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate // Everything went OK coming in, so set the error code. 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate errCode = ServiceLocationException.OK; 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate // By default, the header parses the client side message. A server 2100Sstevel@tonic-gate // side subclass must replace this. We do this so that the amount of code 2110Sstevel@tonic-gate // in the client is minimized, since this class must be in both. 2120Sstevel@tonic-gate parseMsg(DataInputStream dis)2130Sstevel@tonic-gate SrvLocMsg parseMsg(DataInputStream dis) 2140Sstevel@tonic-gate throws ServiceLocationException, 2150Sstevel@tonic-gate IOException, 2160Sstevel@tonic-gate IllegalArgumentException { 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate SrvLocMsg rply = null; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate // Get the error code, if not SAAdvert. 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if (functionCode != SrvLocHeader.SAAdvert) { 2230Sstevel@tonic-gate errCode = (short)getInt(dis); 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate // Switch and convert according to function code. 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate switch (functionCode) { 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate case SrvLocHeader.SrvRply: 2320Sstevel@tonic-gate rply = new CSrvMsg(this, dis); 2330Sstevel@tonic-gate break; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate case SrvLocHeader.AttrRply: 2360Sstevel@tonic-gate rply = new CAttrMsg(this, dis); 2370Sstevel@tonic-gate break; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate case SrvLocHeader.SrvTypeRply: 2400Sstevel@tonic-gate rply = new CSrvTypeMsg(this, dis); 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate case SrvLocHeader.DAAdvert: 2440Sstevel@tonic-gate rply = new CDAAdvert(this, dis); 2450Sstevel@tonic-gate break; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate case SrvLocHeader.SrvAck: 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate // We act as a SrvAck. 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate rply = this; 2520Sstevel@tonic-gate iNumReplies = 1; 2530Sstevel@tonic-gate break; 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate case SrvLocHeader.SAAdvert: 2560Sstevel@tonic-gate rply = new CSAAdvert(this, dis); 2570Sstevel@tonic-gate break; 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate default: 2600Sstevel@tonic-gate throw 2610Sstevel@tonic-gate new ServiceLocationException( 2620Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2630Sstevel@tonic-gate "function_code_error", 2640Sstevel@tonic-gate new Object[] { 2650Sstevel@tonic-gate new Integer(functionCode)}); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate // Check for size overflow. 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate if (nbytes > length) { 2720Sstevel@tonic-gate throw 2730Sstevel@tonic-gate new ServiceLocationException( 2740Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2750Sstevel@tonic-gate "length_overflow", 2760Sstevel@tonic-gate new Object[] { 2770Sstevel@tonic-gate new Integer(nbytes), new Integer(length)}); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate return rply; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate // Construct a header for output. Used by the client side code to 2850Sstevel@tonic-gate // construct an initial request and the server side code to construct 2860Sstevel@tonic-gate // a reply. 2870Sstevel@tonic-gate SLPHeaderV2(int functionCode, boolean fresh, Locale locale)2880Sstevel@tonic-gate SLPHeaderV2(int functionCode, boolean fresh, Locale locale) 2890Sstevel@tonic-gate throws ServiceLocationException { 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate // Check for proper function code and nonnull locale. 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate Assert.slpassert(((functionCode <= SAAdvert) && 2940Sstevel@tonic-gate (functionCode >= SrvReq)), 2950Sstevel@tonic-gate "function_code_error", 2960Sstevel@tonic-gate new Object[] {new Integer(functionCode)}); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate Assert.slpassert((locale != null), 2990Sstevel@tonic-gate "null_locale_error", 3000Sstevel@tonic-gate new Object[0]); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate this.version = Defaults.version; 3030Sstevel@tonic-gate this.functionCode = functionCode; 3040Sstevel@tonic-gate this.locale = locale; 3050Sstevel@tonic-gate this.xid = getUniqueXID(); // client can change it later if they want. 3060Sstevel@tonic-gate this.fresh = fresh; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate // If there's not enough for the error code (if any), then signal 3090Sstevel@tonic-gate // an error. The assumption here is that the message is going 3100Sstevel@tonic-gate // via UDP or multicast. 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate byte[] ltag = 3130Sstevel@tonic-gate getStringBytes(SLPConfig.localeToLangTag(locale), Defaults.UTF8); 3140Sstevel@tonic-gate int headerLen = ltag.length + HEADER_BYTES; 3150Sstevel@tonic-gate int payLen = packetLength - headerLen; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate if (payLen < SHORT_SIZE) { 3180Sstevel@tonic-gate throw 3190Sstevel@tonic-gate new ServiceLocationException( 3200Sstevel@tonic-gate ServiceLocationException.BUFFER_OVERFLOW, 3210Sstevel@tonic-gate "buffer_overflow", 3220Sstevel@tonic-gate new Object[] { 3230Sstevel@tonic-gate new Integer(headerLen + SHORT_SIZE), 3240Sstevel@tonic-gate new Integer(packetLength)}); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate // Externalize the message by converting it to bytes and writing 3290Sstevel@tonic-gate // it to the output stream. 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate public void externalize(ByteArrayOutputStream baos, boolean mcast, boolean isTCP)3320Sstevel@tonic-gate externalize(ByteArrayOutputStream baos, boolean mcast, boolean isTCP) 3330Sstevel@tonic-gate throws ServiceLocationException { 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate // Convert the locale to a tag. We need the length. 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate byte[] ltagBytes = 3380Sstevel@tonic-gate getStringBytes(SLPConfig.localeToLangTag(locale), Defaults.UTF8); 3390Sstevel@tonic-gate int ltagLen = ltagBytes.length; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate // Set the multicast flag. 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate this.mcast = mcast; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate // We need to get stuff into another stream first, so we can correctly 3460Sstevel@tonic-gate // calculate the length. 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate ByteArrayOutputStream bbaos = new ByteArrayOutputStream(); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate // Need to put in the error code. There will only be an error code 3510Sstevel@tonic-gate // if error codes are applicable for this message type. Note 3520Sstevel@tonic-gate // that room for the error code was reserved in the initial 3530Sstevel@tonic-gate // calculation of the header, so there should always be room 3540Sstevel@tonic-gate // for it, even if the packet overflowed otherwise. 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate if (functionCode == SrvLocHeader.SrvAck || 3570Sstevel@tonic-gate functionCode == SrvLocHeader.SrvTypeRply || 3580Sstevel@tonic-gate functionCode == SrvLocHeader.SrvRply || 3590Sstevel@tonic-gate functionCode == SrvLocHeader.AttrRply || 3600Sstevel@tonic-gate functionCode == SrvLocHeader.DAAdvert) { 3610Sstevel@tonic-gate putInt(errCode, bbaos); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate // Put in the previous responders, if there are any. Note that 3660Sstevel@tonic-gate // there may be only when the error code is not put out. 3670Sstevel@tonic-gate // We check against the packet size during parsing so that 3680Sstevel@tonic-gate // we don't overflow the packet and throw a special exception 3690Sstevel@tonic-gate // if an overflow happens. We only put out the previous 3700Sstevel@tonic-gate // responders list if the request is going by multicast, but 3710Sstevel@tonic-gate // we need to put out an empty vector for unicast requests. 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate int prevResLen = 3740Sstevel@tonic-gate packetLength - (payload.length + HEADER_BYTES + ltagLen); 3750Sstevel@tonic-gate Vector resp = previousResponders; 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if (resp != null) { 3780Sstevel@tonic-gate resp = (mcast ? resp:new Vector()); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate parsePreviousRespondersOut(resp, bbaos, prevResLen); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate // If the error code is OK, then insert the rest of the message 3850Sstevel@tonic-gate // and parse the options. If there was an error, 3863517Smp204432 // this step is skipped because the data isn't relevant. 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate if (errCode == ServiceLocationException.OK) { 3890Sstevel@tonic-gate bbaos.write(payload, 0, payload.length); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate // Externalize any options. 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate optOff = externalizeOptions(bbaos, ltagLen); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate byte[] payloadBytes = bbaos.toByteArray(); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate // Set the length here to the actual length of the packet. 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate length = HEADER_BYTES + ltagLen + payloadBytes.length; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate // If we exceed the 24 bit length size, we are hosed. 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate if (length > MAX_MESSAGE_LENGTH) { 4050Sstevel@tonic-gate throw 4060Sstevel@tonic-gate new ServiceLocationException( 4070Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 4080Sstevel@tonic-gate "max_msg_size_exceeded", 4090Sstevel@tonic-gate new Object[0]); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate // Truncate if necessary. We will always have room for a header 4140Sstevel@tonic-gate // and error code because we check when creating the object. 4150Sstevel@tonic-gate // Note that no URL block will be truncated because the spec 4160Sstevel@tonic-gate // says it can't be. 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate if (!isTCP && (length > packetLength)) { 4190Sstevel@tonic-gate overflow = true; 4200Sstevel@tonic-gate length = packetLength; 4210Sstevel@tonic-gate byte[] newBytes = new byte[packetLength]; 4220Sstevel@tonic-gate System.arraycopy(payloadBytes, 0, newBytes, 0, 4230Sstevel@tonic-gate length - (HEADER_BYTES + ltagLen)); 4240Sstevel@tonic-gate payloadBytes = newBytes; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate // 4290Sstevel@tonic-gate // Write out the header. 4300Sstevel@tonic-gate // 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate // Write version and function code. 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate baos.write((byte) (0xFF & version)); 4350Sstevel@tonic-gate baos.write((byte) (0xFF & functionCode)); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate // Put length in. 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate putInt24(length, baos); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate // Put in flags. 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate byte flags = (byte)NOFLAG; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if (overflow) { 4460Sstevel@tonic-gate flags = (byte)(flags | OVERFLOW); 4470Sstevel@tonic-gate } else { 4480Sstevel@tonic-gate flags = (byte)(flags & ~OVERFLOW); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate if (fresh) { 4520Sstevel@tonic-gate flags = (byte)((flags | FRESH) & 0xFF); 4530Sstevel@tonic-gate } else { 4540Sstevel@tonic-gate flags = (byte)((flags & ~FRESH) & 0xFF); 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate if (mcast) { 4580Sstevel@tonic-gate flags = (byte)((flags | MCAST) & 0xFF); 4590Sstevel@tonic-gate } else { 4600Sstevel@tonic-gate flags = (byte)((flags & ~MCAST) & 0xFF); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate // Write out flags. 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate baos.write((byte) (0xFF & flags)); 4660Sstevel@tonic-gate baos.write((byte)0); 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate putInt24(optOff, baos); // write option offset, if any. 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate putInt(xid, baos); // write xid. 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate putInt(ltagLen, baos); // write lang size. 4730Sstevel@tonic-gate baos.write(ltagBytes, 0, ltagBytes.length); // write lang tag. 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate // 4760Sstevel@tonic-gate // Write the body. 4770Sstevel@tonic-gate // 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate baos.write(payloadBytes, 0, payloadBytes.length); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate // 4840Sstevel@tonic-gate // Option handling. 4850Sstevel@tonic-gate // 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate // Parse any options. 4880Sstevel@tonic-gate parseOptions(DataInputStream dsr)4890Sstevel@tonic-gate void parseOptions(DataInputStream dsr) 4900Sstevel@tonic-gate throws ServiceLocationException, 4910Sstevel@tonic-gate IOException, 4920Sstevel@tonic-gate IllegalArgumentException { 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate // If no options return. 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate if (optOff == 0) { 4970Sstevel@tonic-gate return; 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate int optNext = 0; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate // Parse any options in the data stream. 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate do { 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate // Parse extension id. 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate int optId = getInt(dsr); 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate // Parse extension offset. 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate optNext = getInt(dsr); 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate // Lookup an option parser. 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate Integer key = new Integer(optId); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate Class optClass = (Class)optClasses.get(key); 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate // May be an exception if class is null. 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate if (optClass == null) { 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate // In mandatory range. Throw an exception. 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate if ((optId >= MANDATORY_OPTION_LOW) && 5280Sstevel@tonic-gate (optId <= MANDATORY_OPTION_HIGH)) { 5290Sstevel@tonic-gate throw 5300Sstevel@tonic-gate new ServiceLocationException( 5310Sstevel@tonic-gate ServiceLocationException.OPTION_NOT_SUPPORTED, 5320Sstevel@tonic-gate "v2_unsup_option", 5330Sstevel@tonic-gate new Object[] {key}); 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate // Skip the rest of the option. 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate int skipStart = length; 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (optNext != 0) { 5420Sstevel@tonic-gate skipStart = optNext; 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate dsr.skipBytes(skipStart - nbytes); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate } else { 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate try { 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate // Parse the option. 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate OptionParser optParser = 5560Sstevel@tonic-gate (OptionParser)optClass.newInstance(); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate SLPOption opt = optParser.parse(this, dsr); 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate // Insert option into option table. 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate optTable.put(key, opt); 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate } catch (InstantiationException ex) { 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate throw 5670Sstevel@tonic-gate new ServiceLocationException( 5680Sstevel@tonic-gate ServiceLocationException.INTERNAL_SYSTEM_ERROR, 5690Sstevel@tonic-gate "v2_option_inst", 5700Sstevel@tonic-gate new Object[] {key, ex}); 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate } catch (IllegalAccessException ex) { 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate throw 5750Sstevel@tonic-gate new ServiceLocationException( 5760Sstevel@tonic-gate ServiceLocationException.INTERNAL_SYSTEM_ERROR, 5770Sstevel@tonic-gate "v2_option_sec", 5780Sstevel@tonic-gate new Object[] {key, ex}); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate } while (optNext != 0); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate // Externalize any options. 5850Sstevel@tonic-gate externalizeOptions(ByteArrayOutputStream baos, int langTagLen)5860Sstevel@tonic-gate private int externalizeOptions(ByteArrayOutputStream baos, int langTagLen) 5870Sstevel@tonic-gate throws ServiceLocationException { 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate // Calculate offset to options, if any. 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate int toOpt = 0; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate if (optTable.size() <= 0) { 5940Sstevel@tonic-gate return toOpt; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate toOpt = HEADER_BYTES + langTagLen + baos.size(); 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate // For all options in the table, parse them out. 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate Enumeration en = optTable.keys(); 6030Sstevel@tonic-gate int nextOpt = toOpt; 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate while (en.hasMoreElements()) { 6060Sstevel@tonic-gate Integer id = (Integer)en.nextElement(); 6070Sstevel@tonic-gate SLPOption opt = (SLPOption)optTable.get(id); 6080Sstevel@tonic-gate ByteArrayOutputStream obaos = new ByteArrayOutputStream(); 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate // Linearize option object. 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate opt.externalize(this, obaos); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate // Calculate offset to next options. 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate nextOpt += obaos.size() + OPT_ID_SIZE + OPT_OFF_SIZE; 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate // Plop it into the output stream. 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate putInt(id.intValue(), baos); 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate // Check whether there are more options first. If so, then 6240Sstevel@tonic-gate // the next offset is zero. 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate if (en.hasMoreElements()) { 6270Sstevel@tonic-gate putInt(nextOpt, baos); 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate } else { 6300Sstevel@tonic-gate putInt(0, baos); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate byte[] bytes = obaos.toByteArray(); 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate baos.write(bytes, 0, bytes.length); 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate return toOpt; 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate // Parse the previous responder list out, being sure to truncate 6440Sstevel@tonic-gate // so the list is syntactically correct if there is an overflow. 6450Sstevel@tonic-gate // This duplicates the comma separated list code to a certain 6460Sstevel@tonic-gate // extent. 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate private void parsePreviousRespondersOut(Vector resp, ByteArrayOutputStream baos, int available)6490Sstevel@tonic-gate parsePreviousRespondersOut(Vector resp, 6500Sstevel@tonic-gate ByteArrayOutputStream baos, 6510Sstevel@tonic-gate int available) 6520Sstevel@tonic-gate throws ServiceLocationException { 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate ByteArrayOutputStream bbaos = new ByteArrayOutputStream(); 6550Sstevel@tonic-gate int i, n = resp.size(); 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate for (i = 0; i < n; i++) { 6580Sstevel@tonic-gate String address = (String)resp.elementAt(i); 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate // Add comma if necessary. 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if (i > 0) { 6630Sstevel@tonic-gate address = "," + address; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate // Convert to UTF8 bytes. 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate byte[] bytes = getStringBytes(address, Defaults.UTF8); 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate // Write bytes to stream if there's room. 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate if (bytes.length <= available) { 6740Sstevel@tonic-gate bbaos.write(bytes, 0, bytes.length); 6750Sstevel@tonic-gate available = available - bytes.length; 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate } else { 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate // Throw exception, upper layers need to break off multicast. 6800Sstevel@tonic-gate // This exception should *never* be surfaced. 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate throw 6830Sstevel@tonic-gate new ServiceLocationException( 6840Sstevel@tonic-gate ServiceLocationException.PREVIOUS_RESPONDER_OVERFLOW, 6850Sstevel@tonic-gate "v2_prev_resp_overflow", 6860Sstevel@tonic-gate new Object[] {}); 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate // Now write to the real stream. 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate byte[] out = bbaos.toByteArray(); 6930Sstevel@tonic-gate putInt(out.length, baos); 6940Sstevel@tonic-gate baos.write(out, 0, out.length); 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate nbytes += out.length; 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate // 7010Sstevel@tonic-gate // Utilities for parsing service URL's and attribute lists, with 7020Sstevel@tonic-gate // authentication information. 7030Sstevel@tonic-gate // 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate // Parse in a service URL including lifetime if necessary. 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate ServiceURL parseServiceURLIn(DataInputStream dis, Hashtable authTable, short err)7080Sstevel@tonic-gate parseServiceURLIn(DataInputStream dis, 7090Sstevel@tonic-gate Hashtable authTable, 7100Sstevel@tonic-gate short err) 7110Sstevel@tonic-gate throws ServiceLocationException, IOException { 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate // Ignore reserved byte. 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate byte[] b = new byte[1]; 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate dis.readFully(b, 0, 1); 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate nbytes += 1; 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate // Get URL lifetime. 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate int lifetime = getInt(dis); 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate // Get URL. 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate StringBuffer buf = new StringBuffer(); 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate byte[] rawBytes = getString(buf, dis); 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate // Get auth block, if any. 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate Hashtable auth = null; 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate // Get number of auth blocks. 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate b = new byte[1]; 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate dis.readFully(b, 0, 1); 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate nbytes += 1; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate byte nauths = (byte)(b[0] & 0xFF); 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate if (nauths > 0) { 7460Sstevel@tonic-gate ByteArrayOutputStream abaos = new ByteArrayOutputStream(); 7470Sstevel@tonic-gate putInteger(rawBytes.length, abaos); 7480Sstevel@tonic-gate Object[] message = new Object[2]; 7490Sstevel@tonic-gate message[0] = abaos.toByteArray(); 7500Sstevel@tonic-gate message[1] = rawBytes; 7510Sstevel@tonic-gate auth = getCheckedAuthBlockList(message, nauths, dis); 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate lifetime = AuthBlock.getShortestLifetime(auth); 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate String ssurl = buf.toString(); 7580Sstevel@tonic-gate ServiceURL url = null; 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate try { 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate url = new ServiceURL(ssurl, lifetime); 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate } catch (IllegalArgumentException ex) { 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate throw 7670Sstevel@tonic-gate new ServiceLocationException(err, 7680Sstevel@tonic-gate "malformed_url", 7690Sstevel@tonic-gate new Object[] {ex.getMessage()}); 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate if (auth != null) { 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate // Put it in the auth block for this URL. 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate authTable.put(url, auth); 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate return url; 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate // Parse out a service URL, create authentication blocks if necessary. 7850Sstevel@tonic-gate // Return true if the URL was output. Check that we don't overflow 7860Sstevel@tonic-gate // packet size in the middle. 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate boolean parseServiceURLOut(ServiceURL surl, boolean urlAuth, Hashtable auth, ByteArrayOutputStream baos, boolean checkOverflow)7890Sstevel@tonic-gate parseServiceURLOut(ServiceURL surl, 7900Sstevel@tonic-gate boolean urlAuth, 7910Sstevel@tonic-gate Hashtable auth, 7920Sstevel@tonic-gate ByteArrayOutputStream baos, 7930Sstevel@tonic-gate boolean checkOverflow) 7940Sstevel@tonic-gate throws ServiceLocationException { 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate // We need to keep track of size, so we don't overflow packet length. 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate ByteArrayOutputStream bbaos = new ByteArrayOutputStream(); 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate int mbytes = nbytes; 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate // Convert the URL to bytes. 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate byte[] bytes = getStringBytes(surl.toString(), Defaults.UTF8); 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate // Parse out reserved. 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate bbaos.write((byte)(0xFF & 0)); 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate nbytes += 1; 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate // Parse out the lifetime. 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate putInt(surl.getLifetime(), bbaos); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate byte bs = (byte)0; 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate // Process auth block list if required. 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate if (urlAuth) { 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate // Create an auth block if necessary. 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate if (auth == null) { 8250Sstevel@tonic-gate ByteArrayOutputStream abaos = new ByteArrayOutputStream(); 8260Sstevel@tonic-gate putInteger(bytes.length, abaos); 8270Sstevel@tonic-gate Object[] message = new Object[2]; 8280Sstevel@tonic-gate message[0] = abaos.toByteArray(); 8290Sstevel@tonic-gate message[1] = bytes; 8300Sstevel@tonic-gate auth = getCheckedAuthBlockList(message, surl.getLifetime()); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate bs = (byte) auth.size(); 8350Sstevel@tonic-gate Object[] bytesArray = AuthBlock.getContents(auth); 8360Sstevel@tonic-gate bytes = (byte[]) bytesArray[1]; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate // Put out the URL bytes. 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate putInt(bytes.length, bbaos); 8430Sstevel@tonic-gate bbaos.write(bytes, 0, bytes.length); 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate nbytes += bytes.length; 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate // Write auth block size. 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate bbaos.write((byte)(0xFF & bs)); 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate nbytes += 1; 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate // If there are auth blocks required, put them out now. 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate if (bs > (byte)0) { 8560Sstevel@tonic-gate AuthBlock.externalizeAll(this, auth, bbaos); 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate // If we can, write it out. 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate bytes = bbaos.toByteArray(); 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate if (!checkOverflow || nbytes <= packetLength) { 8650Sstevel@tonic-gate baos.write(bytes, 0, bytes.length); 8660Sstevel@tonic-gate return true; // nbytes already set... 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate } else { 8690Sstevel@tonic-gate nbytes = mbytes; // truncate... 8700Sstevel@tonic-gate return false; 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate // Parse in a potentially authenticated attribute list. 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate Hashtable parseAuthenticatedAttributeVectorIn(Vector attrs, DataInputStream dis, boolean allowMultiValuedBooleans)8780Sstevel@tonic-gate parseAuthenticatedAttributeVectorIn(Vector attrs, 8790Sstevel@tonic-gate DataInputStream dis, 8800Sstevel@tonic-gate boolean allowMultiValuedBooleans) 8810Sstevel@tonic-gate throws ServiceLocationException, IOException { 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate // First, parse in the attribute vector. 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate byte[] rawBytes = 8860Sstevel@tonic-gate parseAttributeVectorIn(attrs, dis, allowMultiValuedBooleans); 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate ByteArrayOutputStream abaos = new ByteArrayOutputStream(); 8890Sstevel@tonic-gate putInteger(rawBytes.length, abaos); 8900Sstevel@tonic-gate Object[] message = new Object[2]; 8910Sstevel@tonic-gate message[0] = abaos.toByteArray(); 8920Sstevel@tonic-gate message[1] = rawBytes; 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate // Get the attribute list signature, if necessary. 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate return parseSignatureIn(message, dis); 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate // Parse in a list of attributes into attrs, returing raw bytes. 9010Sstevel@tonic-gate // ServiceLocationAttribute objects. Clients take care of auth blocks. 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate byte[] parseAttributeVectorIn(Vector attrs, DataInputStream dis, boolean allowMultiValuedBooleans)9040Sstevel@tonic-gate parseAttributeVectorIn(Vector attrs, 9050Sstevel@tonic-gate DataInputStream dis, 9060Sstevel@tonic-gate boolean allowMultiValuedBooleans) 9070Sstevel@tonic-gate throws ServiceLocationException, IOException { 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate StringBuffer buf = new StringBuffer(); 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate byte[] rawBytes = getString(buf, dis); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate // Parse the list into ServiceLocationAttribute objects. 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate Vector attrForms = parseCommaSeparatedListIn(buf.toString(), false); 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate int i, n = attrForms.size(); 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate for (i = 0; i < n; i++) { 9200Sstevel@tonic-gate String attrForm = 9210Sstevel@tonic-gate (String)attrForms.elementAt(i); 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate attrs.addElement( 9240Sstevel@tonic-gate new ServiceLocationAttribute( 9250Sstevel@tonic-gate attrForm, allowMultiValuedBooleans)); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate return rawBytes; 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate // Parse out a vector of ServiceLocationAttributes. Includes escaping 9320Sstevel@tonic-gate // characters. 9330Sstevel@tonic-gate byte[] parseAttributeVectorOut(Vector v, int lifetime, boolean attrAuth, Hashtable auth, ByteArrayOutputStream baos, boolean writeAuthCount)9340Sstevel@tonic-gate parseAttributeVectorOut(Vector v, 9350Sstevel@tonic-gate int lifetime, 9360Sstevel@tonic-gate boolean attrAuth, 9370Sstevel@tonic-gate Hashtable auth, 9380Sstevel@tonic-gate ByteArrayOutputStream baos, 9390Sstevel@tonic-gate boolean writeAuthCount) 9400Sstevel@tonic-gate throws ServiceLocationException { 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate byte[] bytes = null; 9430Sstevel@tonic-gate int nBlocks = 0; 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate // Convert attribute vector to comma separated list. 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate if (!attrAuth || auth == null) { 9480Sstevel@tonic-gate Vector strings = new Vector(); 9490Sstevel@tonic-gate Enumeration en = v.elements(); 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate // Convert the attributes to strings, escaping characters to 9520Sstevel@tonic-gate // escape. 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate while (en.hasMoreElements()) { 9550Sstevel@tonic-gate ServiceLocationAttribute attr = 9560Sstevel@tonic-gate (ServiceLocationAttribute)en.nextElement(); 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate strings.addElement(attr.externalize()); 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate // Create the comma separated list. 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate String clist = vectorToCommaSeparatedList(strings); 9650Sstevel@tonic-gate bytes = getStringBytes(clist, Defaults.UTF8); 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate if (attrAuth) { 9680Sstevel@tonic-gate ByteArrayOutputStream abaos = new ByteArrayOutputStream(); 9690Sstevel@tonic-gate putInteger(bytes.length, abaos); 9700Sstevel@tonic-gate Object[] message = new Object[2]; 9710Sstevel@tonic-gate message[0] = abaos.toByteArray(); 9720Sstevel@tonic-gate message[1] = bytes; 9730Sstevel@tonic-gate auth = getCheckedAuthBlockList(message, lifetime); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate } else { 9760Sstevel@tonic-gate Object[] bytesArray = AuthBlock.getContents(auth); 9770Sstevel@tonic-gate bytes = (byte[]) bytesArray[1]; 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate // Get number of blocks if authentication. 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate if (auth != null) { 9840Sstevel@tonic-gate nBlocks = auth.size(); 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate // Write out the bytes. 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate putInt(bytes.length, baos); 9920Sstevel@tonic-gate baos.write(bytes, 0, bytes.length); 9930Sstevel@tonic-gate nbytes += bytes.length; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate // Write out number of auth blocks. 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate if (writeAuthCount) { 9980Sstevel@tonic-gate baos.write((byte)(nBlocks & 0xFF)); 9990Sstevel@tonic-gate nbytes += 1; 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate // Write out the attribute authentication blocks. 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate if (attrAuth && nBlocks > 0) { 10050Sstevel@tonic-gate AuthBlock.externalizeAll(this, auth, baos); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate return bytes; 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate // Get an auth block list, checking first for security. 10120Sstevel@tonic-gate getCheckedAuthBlockList(Object[] message, int lifetime)10130Sstevel@tonic-gate Hashtable getCheckedAuthBlockList(Object[] message, int lifetime) 10140Sstevel@tonic-gate throws ServiceLocationException { 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate if (!SLPConfig.getSLPConfig().getHasSecurity()) { 10170Sstevel@tonic-gate throw 10180Sstevel@tonic-gate new ServiceLocationException( 10190Sstevel@tonic-gate ServiceLocationException.AUTHENTICATION_ABSENT, 10200Sstevel@tonic-gate "auth_classes_missing", 10210Sstevel@tonic-gate new Object[0]); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate return AuthBlock.makeAuthBlocks(message, lifetime); 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate // Get an SLPAuthBlockList, checking first if security is enabled. 10280Sstevel@tonic-gate getCheckedAuthBlockList(Object[] message, byte nauth, DataInputStream dis)10290Sstevel@tonic-gate Hashtable getCheckedAuthBlockList(Object[] message, 10300Sstevel@tonic-gate byte nauth, 10310Sstevel@tonic-gate DataInputStream dis) 10320Sstevel@tonic-gate throws ServiceLocationException, IOException { 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate if (!SLPConfig.getSLPConfig().getHasSecurity()) { 10350Sstevel@tonic-gate throw 10360Sstevel@tonic-gate new ServiceLocationException( 10370Sstevel@tonic-gate ServiceLocationException.AUTHENTICATION_ABSENT, 10380Sstevel@tonic-gate "auth_classes_missing", 10390Sstevel@tonic-gate new Object[0]); 10400Sstevel@tonic-gate } 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate return AuthBlock.makeAuthBlocks(this, message, dis, nauth); 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate // Parse in an attribute signature. 10460Sstevel@tonic-gate parseSignatureIn(Object[] message, DataInputStream dis)10470Sstevel@tonic-gate Hashtable parseSignatureIn(Object[] message, DataInputStream dis) 10480Sstevel@tonic-gate throws ServiceLocationException, IOException { 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate Hashtable auth = null; 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate byte[] b = new byte[1]; 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate dis.readFully(b, 0, 1); 10550Sstevel@tonic-gate nbytes += 1; 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate byte nauths = (byte)(b[0] & 0xFF); 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate if (nauths > 0) { 10600Sstevel@tonic-gate auth = getCheckedAuthBlockList(message, nauths, dis); 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate } 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate return auth; 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate // 10680Sstevel@tonic-gate // Utility functions to help with verification of data. 10690Sstevel@tonic-gate // 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate // Escape tags, check for strings. Trim trailing, leading whitespace, 10720Sstevel@tonic-gate // since it is ignored for matching purposes and tags are only 10730Sstevel@tonic-gate // used for matching. 10740Sstevel@tonic-gate escapeTags(Vector t)10750Sstevel@tonic-gate void escapeTags(Vector t) 10760Sstevel@tonic-gate throws ServiceLocationException { 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate int i, n = t.size(); 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate for (i = 0; i < n; i++) { 10810Sstevel@tonic-gate Object o = t.elementAt(i); 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate if (o instanceof String) { 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate // Escape tag. 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate String tag = 10880Sstevel@tonic-gate ServiceLocationAttribute.escapeAttributeString((String)o, 10890Sstevel@tonic-gate false); 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate t.setElementAt(tag.trim(), i); 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate } else { 10940Sstevel@tonic-gate throw 10950Sstevel@tonic-gate new IllegalArgumentException( 10960Sstevel@tonic-gate SLPConfig.getSLPConfig().formatMessage("nonstring_tag", 10970Sstevel@tonic-gate new Object[0])); 10980Sstevel@tonic-gate } 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate } 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate // Unescape tags. Trim trailing and leading whitespace since it is 11030Sstevel@tonic-gate // ignored for matching purposes and tags are only used for matching. 11040Sstevel@tonic-gate unescapeTags(Vector t)11050Sstevel@tonic-gate void unescapeTags(Vector t) 11060Sstevel@tonic-gate throws ServiceLocationException { 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate int i, n = t.size(); 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate for (i = 0; i < n; i++) { 11110Sstevel@tonic-gate String tag = (String)t.elementAt(i); 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate tag = 11140Sstevel@tonic-gate ServiceLocationAttribute.unescapeAttributeString(tag, false); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate t.setElementAt(tag.trim(), i); 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate } 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate // Escape vector of scope strings. 11210Sstevel@tonic-gate escapeScopeStrings(Vector scopes)11220Sstevel@tonic-gate static void escapeScopeStrings(Vector scopes) 11230Sstevel@tonic-gate throws ServiceLocationException { 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate int i, n = scopes.size(); 11260Sstevel@tonic-gate Vector ret = new Vector(); 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate for (i = 0; i < n; i++) { 11290Sstevel@tonic-gate String scope = (String)scopes.elementAt(i); 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate scopes.setElementAt( 11320Sstevel@tonic-gate ServiceLocationAttribute.escapeAttributeString(scope, false), 11330Sstevel@tonic-gate i); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate // Unescape vector of scope strings. 11380Sstevel@tonic-gate unescapeScopeStrings(Vector scopes)11390Sstevel@tonic-gate static void unescapeScopeStrings(Vector scopes) 11400Sstevel@tonic-gate throws ServiceLocationException { 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate int i, n = scopes.size(); 11430Sstevel@tonic-gate Vector ret = new Vector(); 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate for (i = 0; i < n; i++) { 11460Sstevel@tonic-gate String scope = (String)scopes.elementAt(i); 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate scopes.setElementAt( 11490Sstevel@tonic-gate ServiceLocationAttribute.unescapeAttributeString(scope, false), 11500Sstevel@tonic-gate i); 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate } 11530Sstevel@tonic-gate 11540Sstevel@tonic-gate // Error if somebody tries to do this client side. 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate SDAAdvert getDAAdvert(short xid, long timestamp, ServiceURL url, Vector scopes, Vector attrs)11570Sstevel@tonic-gate getDAAdvert(short xid, 11580Sstevel@tonic-gate long timestamp, 11590Sstevel@tonic-gate ServiceURL url, 11600Sstevel@tonic-gate Vector scopes, 11610Sstevel@tonic-gate Vector attrs) 11620Sstevel@tonic-gate throws ServiceLocationException { 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate Assert.slpassert(false, 11650Sstevel@tonic-gate "v2_daadvert_client_side", 11660Sstevel@tonic-gate new Object[0]); 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate return null; // never get here... 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate // Reimplement clone() to get the header size right. 11720Sstevel@tonic-gate clone()11730Sstevel@tonic-gate public Object clone() 11740Sstevel@tonic-gate throws CloneNotSupportedException { 11750Sstevel@tonic-gate SLPHeaderV2 hdr = (SLPHeaderV2)super.clone(); 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate byte[] langBytes = getStringBytes(locale.toString(), 11780Sstevel@tonic-gate Defaults.UTF8); 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate hdr.nbytes = HEADER_BYTES + langBytes.length + 2; // for error code... 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate return hdr; 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate } 1185