xref: /onnv-gate/usr/src/lib/libslp/javalib/com/sun/slp/SLPHeaderV1.java (revision 7298:b69e27387f74)
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 2001-2002 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate //  SLPHeaderV1.java: SLPv1 Header.
280Sstevel@tonic-gate //  Author:           James Kempf
290Sstevel@tonic-gate //  Created On:       Thu Sep 10 15:12:14 1998
300Sstevel@tonic-gate //  Last Modified By: James Kempf
310Sstevel@tonic-gate //  Last Modified On: Wed Jan 20 15:38:07 1999
320Sstevel@tonic-gate //  Update Count:     59
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 import java.io.*;
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /**
410Sstevel@tonic-gate  * The SLPHeaderV1 class models the SLPv1 server side header.
420Sstevel@tonic-gate  *
430Sstevel@tonic-gate  * @author James Kempf
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate class SLPHeaderV1 extends SrvLocHeader implements Cloneable {
470Sstevel@tonic-gate 
480Sstevel@tonic-gate     // Version number.
490Sstevel@tonic-gate 
500Sstevel@tonic-gate     static int VERSION = 1;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate     // Function code for message reply.
530Sstevel@tonic-gate 
540Sstevel@tonic-gate     int replyFunctionCode = SrvLocHeader.SrvAck;
550Sstevel@tonic-gate 
560Sstevel@tonic-gate     // Various header flags.
570Sstevel@tonic-gate 
580Sstevel@tonic-gate     protected static final int NOFLAG   = 0x00;
590Sstevel@tonic-gate     protected static final int OVERFLOW = 0x80;
600Sstevel@tonic-gate     protected static final int MONOLING = 0x40;
610Sstevel@tonic-gate     protected static final int URLSIG   = 0x20;
620Sstevel@tonic-gate     protected static final int ATTRSIG  = 0x10;
630Sstevel@tonic-gate     protected static final int FRESH    = 0x08;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate     protected static int LANG_CODE_BYTES = 2;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate     protected static int HEADER_BYTES =
680Sstevel@tonic-gate 	VERSION_FUNCTION_BYTES + LANG_CODE_BYTES + 8;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate     // Characters to escape.
710Sstevel@tonic-gate 
720Sstevel@tonic-gate     final private static String UNESCAPABLE_CHARS = ",=!></*()";
730Sstevel@tonic-gate     final private static String ESCAPABLE_CHARS =
740Sstevel@tonic-gate 	UNESCAPABLE_CHARS + "&#;";
750Sstevel@tonic-gate 
760Sstevel@tonic-gate     String charCode = IANACharCode.UTF8;	// character encoding.
770Sstevel@tonic-gate     boolean monolingual = false;		// monolingual flag.
780Sstevel@tonic-gate 
790Sstevel@tonic-gate     // Used to construct a header in SrvLocHeader.newInstance().
800Sstevel@tonic-gate 
SLPHeaderV1()810Sstevel@tonic-gate     SLPHeaderV1() {
820Sstevel@tonic-gate 	super();
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	version = VERSION;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate     }
870Sstevel@tonic-gate 
880Sstevel@tonic-gate     // Assign reply code based on function code type, then use superclass
890Sstevel@tonic-gate     //  method to parse header.
900Sstevel@tonic-gate 
parseHeader(int functionCode, DataInputStream dis)910Sstevel@tonic-gate     void parseHeader(int functionCode, DataInputStream dis)
920Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	this.functionCode = functionCode;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	// We ignore the error case here.
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	switch (functionCode) {
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	case SrvLocHeader.SrvReq:
1010Sstevel@tonic-gate 	    replyFunctionCode = SrvLocHeader.SrvRply;
1020Sstevel@tonic-gate 	    break;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	case SrvLocHeader.AttrRqst:
1050Sstevel@tonic-gate 	    replyFunctionCode = SrvLocHeader.AttrRply;
1060Sstevel@tonic-gate 	    break;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	case SrvLocHeader.SrvTypeRqst:
1090Sstevel@tonic-gate 	    replyFunctionCode = SrvLocHeader.SrvTypeRply;
1100Sstevel@tonic-gate 	    break;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	length     = getInt(dis);
1150Sstevel@tonic-gate 	byte flags   = (byte) ((char)dis.read() & 0xFF);
1160Sstevel@tonic-gate 	nbytes++;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	overflow = ((flags & OVERFLOW) != 0x00);
1190Sstevel@tonic-gate 	fresh = false; // fresh gets set on output in SLPv1
1200Sstevel@tonic-gate 	monolingual = ((flags & MONOLING) != 0x00);
1210Sstevel@tonic-gate 	boolean urlAuth = ((flags & URLSIG) != 0x00);
1220Sstevel@tonic-gate 	boolean attrAuth = ((flags & ATTRSIG) != 0x00);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	// Security not handled for SLPv1.
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (urlAuth || attrAuth) {
1270Sstevel@tonic-gate 	    throw
1280Sstevel@tonic-gate 		new ServiceLocationException(
1290Sstevel@tonic-gate 				ServiceLocationException.AUTHENTICATION_FAILED,
1300Sstevel@tonic-gate 				"v1_no_security",
1310Sstevel@tonic-gate 				new Object[0]);
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	int dialect    = (int) ((char)dis.read() & 0xFF);
1350Sstevel@tonic-gate 	nbytes++;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	// Dialect must be zero.
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if (dialect != 0) {
1400Sstevel@tonic-gate 	    throw
1410Sstevel@tonic-gate 		new ServiceLocationException(
1420Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
1430Sstevel@tonic-gate 				"v1_nonzero_dialect",
1440Sstevel@tonic-gate 				new Object[0]);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	byte a_bTemp[] = new byte[LANG_CODE_BYTES];
1490Sstevel@tonic-gate 	a_bTemp[0] = (byte) dis.read();
1500Sstevel@tonic-gate 	a_bTemp[1] = (byte) dis.read();
1510Sstevel@tonic-gate 	nbytes += 2;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	try {
1540Sstevel@tonic-gate 	    locale = new Locale(new String(a_bTemp, IANACharCode.ASCII), "");
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	} catch (UnsupportedEncodingException ex) {
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	int intCharCode = getInt(dis);
1610Sstevel@tonic-gate 	charCode = IANACharCode.decodeCharacterEncoding(intCharCode);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	xid     = (short)getInt(dis);
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	errCode = ServiceLocationException.OK;
1660Sstevel@tonic-gate     }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate     // Parse an incoming V1 message and return the SrvLocMsg object.
1690Sstevel@tonic-gate 
parseMsg(DataInputStream dis)1700Sstevel@tonic-gate     SrvLocMsg parseMsg(DataInputStream dis)
1710Sstevel@tonic-gate 	throws ServiceLocationException,
1720Sstevel@tonic-gate 	       IOException,
1730Sstevel@tonic-gate 	       IllegalArgumentException {
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	SrvLocMsg msg = null;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	// If this is a *multicast* request, we reject it except for DAAdvert.
1780Sstevel@tonic-gate 	//  Multicast requests are only taken by SA servers.
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if (mcast && (functionCode != SrvLocHeader.DAAdvert)) {
1810Sstevel@tonic-gate 	    return null;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	// Switch and convert according to function code.
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	switch (functionCode) {
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	case SrvLocHeader.SrvReq:
1900Sstevel@tonic-gate 	    msg = new SLPV1SSrvMsg(this, dis);
1910Sstevel@tonic-gate 	    break;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	case SrvLocHeader.SrvReg:
1940Sstevel@tonic-gate 	    msg = new SLPV1SSrvReg(this, dis);
1950Sstevel@tonic-gate 	    break;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	case SrvLocHeader.SrvDereg:
1980Sstevel@tonic-gate 	    msg = new SLPV1SSrvDereg(this, dis);
1990Sstevel@tonic-gate 	    break;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	case SrvLocHeader.AttrRqst:
2020Sstevel@tonic-gate 	    msg = new SLPV1SAttrMsg(this, dis);
2030Sstevel@tonic-gate 	    break;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	case SrvLocHeader.SrvTypeRqst:
2060Sstevel@tonic-gate 	    msg = new SLPV1SSrvTypeMsg(this, dis);
2070Sstevel@tonic-gate 	    break;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	case SrvLocHeader.DAAdvert:
2100Sstevel@tonic-gate 	    msg = new SLPV1CDAAdvert(this, dis);
2110Sstevel@tonic-gate 	    break;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	default:
2140Sstevel@tonic-gate 	    throw
2150Sstevel@tonic-gate 		new ServiceLocationException(
2160Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
2170Sstevel@tonic-gate 				"function_code_error",
2180Sstevel@tonic-gate 				new Object[] {
2190Sstevel@tonic-gate 		    new Integer(functionCode)});
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	// Check for size overflow.
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	if (nbytes > length) {
2260Sstevel@tonic-gate 	    throw
2270Sstevel@tonic-gate 		new ServiceLocationException(
2280Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
2290Sstevel@tonic-gate 				"length_overflow",
2300Sstevel@tonic-gate 				new Object[] {
2310Sstevel@tonic-gate 		    new Integer(nbytes), new Integer(length)});
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return msg;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate     }
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate     // Externalize the message by converting it to bytes and writing
2400Sstevel@tonic-gate     //  it to the output stream.
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate     public void
externalize(ByteArrayOutputStream baos, boolean mcast, boolean isTCP)2430Sstevel@tonic-gate 	externalize(ByteArrayOutputStream baos, boolean mcast, boolean isTCP)
2440Sstevel@tonic-gate 	throws ServiceLocationException {
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	// Need to put in the error code or previous responders.
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	ByteArrayOutputStream fin = new ByteArrayOutputStream();
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	if (functionCode == SrvLocHeader.SrvAck ||
2510Sstevel@tonic-gate 	    functionCode == SrvLocHeader.SrvTypeRply ||
2520Sstevel@tonic-gate 	    functionCode == SrvLocHeader.SrvRply ||
2530Sstevel@tonic-gate 	    functionCode == SrvLocHeader.AttrRply ||
2540Sstevel@tonic-gate 	    functionCode == SrvLocHeader.DAAdvert) {
2550Sstevel@tonic-gate 	    putInt(errCode, fin);
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	} else {
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	    // Parse out previous responders. Note there will only be some
2600Sstevel@tonic-gate 	    //  if the error code is not put out.
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	    if (previousResponders != null) {
2630Sstevel@tonic-gate 		parseCommaSeparatedListOut(previousResponders, fin);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	    }
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	// Parse payload out if error code is OK and payload is nonnull.
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	if (payload != null && errCode == ServiceLocationException.OK) {
2710Sstevel@tonic-gate 	    fin.write(payload, 0, payload.length);
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	// Don't touch payload here, somebody may put in a previousResponder
2750Sstevel@tonic-gate 	//  and resend the message.
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	byte[] npayload = fin.toByteArray();
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	// Set overflow flag if buffer is too large and this isn't going out
2800Sstevel@tonic-gate 	//  via TCP.
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	if (((npayload.length + 12) > SLPConfig.getSLPConfig().getMTU()) &&
2830Sstevel@tonic-gate 	    !isTCP) {
2840Sstevel@tonic-gate 	    overflow = true;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	baos.write((byte) (0xFF & version));
2890Sstevel@tonic-gate 	nbytes++;
2900Sstevel@tonic-gate 	baos.write((byte) (0xFF & functionCode));
2910Sstevel@tonic-gate 	nbytes++;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	length = npayload.length +12; // the 12 is the length of this header!
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	putInt(length, baos);  // what about overflow???
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	byte flags = 0X00;
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	if (overflow) {
3000Sstevel@tonic-gate 	    flags = (byte)(flags | OVERFLOW);
3010Sstevel@tonic-gate 	} else {
3020Sstevel@tonic-gate 	    flags = (byte)(flags & ~OVERFLOW);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	if (monolingual) {
3060Sstevel@tonic-gate 	    flags = (byte)(flags | MONOLING);
3070Sstevel@tonic-gate 	} else {
3080Sstevel@tonic-gate 	    flags = (byte)(flags & ~MONOLING);
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	if (fresh) {
3120Sstevel@tonic-gate 	    flags = (byte)((flags | FRESH) & 0XFF);
3130Sstevel@tonic-gate 	} else {
3140Sstevel@tonic-gate 	    flags = (byte)((flags & ~FRESH) & 0XFF);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	baos.write((byte) (0xFF & flags));
3180Sstevel@tonic-gate 	nbytes++;
3190Sstevel@tonic-gate 	baos.write((byte) (0xFF & 0)); // dialect...
3200Sstevel@tonic-gate 	nbytes++;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	String language = locale.getLanguage();
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	baos.write((byte) (0xFF & language.charAt(0)));
3250Sstevel@tonic-gate 	baos.write((byte) (0xFF & language.charAt(1)));
3260Sstevel@tonic-gate 	nbytes += 2;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	int intCharCode = 0;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	try {
3310Sstevel@tonic-gate 	    intCharCode = IANACharCode.encodeCharacterEncoding(charCode);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
3340Sstevel@tonic-gate 	    Assert.slpassert(false,
3350Sstevel@tonic-gate 			  "v1_unsupported_encoding",
3360Sstevel@tonic-gate 			  new Object[] {charCode});
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	putInt(intCharCode, baos);
3410Sstevel@tonic-gate 	putInt(xid, baos);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	// Write the body.
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	baos.write(npayload, 0, npayload.length);
3460Sstevel@tonic-gate 	nbytes += npayload.length;
3470Sstevel@tonic-gate     }
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate     // Create an error reply using the reply code. Calculate the
3500Sstevel@tonic-gate     //  error code using the exception.
3510Sstevel@tonic-gate 
makeErrorReply(Exception ex)3520Sstevel@tonic-gate     SrvLocMsg makeErrorReply(Exception ex) {
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	// If this is a DAAdvert, then no error reply is returned
3550Sstevel@tonic-gate 	//  because V1 doesn't support unicast SrvRqst for DAAdvert.
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if (functionCode == SrvLocHeader.DAAdvert) {
3580Sstevel@tonic-gate 	    return null;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	// Clone the header to make sure that everything else is the same.
3630Sstevel@tonic-gate 	//  We don't want to use the same header because it may be tested
3640Sstevel@tonic-gate 	//  elsewhere.
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	SLPHeaderV1 hdr = null;
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	try {
3690Sstevel@tonic-gate 	    hdr = (SLPHeaderV1)this.clone();
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	} catch (CloneNotSupportedException exx) {
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	    // We know we support it.
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	hdr.fresh = false;
3780Sstevel@tonic-gate 	hdr.overflow = false;
3790Sstevel@tonic-gate 	hdr.mcast = false;
3800Sstevel@tonic-gate 	hdr.functionCode = replyFunctionCode;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	// We should *not* be getting a null exception down this path!
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	Assert.slpassert(ex != null,
3850Sstevel@tonic-gate 		      "null_parameter",
3860Sstevel@tonic-gate 		      new Object[] {ex});
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	if (ex instanceof ServiceLocationException) {
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	    hdr.errCode = ((ServiceLocationException)ex).getErrorCode();
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	    // Handle monolingual bit here. If the exception is
3930Sstevel@tonic-gate 	    //  LANGUAGE_NOT_SUPPORTED and the message type is
3940Sstevel@tonic-gate 	    //  either SrvRqst or AttrRqst, then we simply return an
3950Sstevel@tonic-gate 	    //  empty message unless the monolingual flag is on.
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	    if (hdr.errCode ==
3980Sstevel@tonic-gate 		ServiceLocationException.LANGUAGE_NOT_SUPPORTED) {
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		try {
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		    if (!hdr.monolingual) {
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 			if (hdr.functionCode == SrvLocHeader.SrvReq) {
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 			    return SLPV1SSrvMsg.makeEmptyReply(hdr);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 			} else if (hdr.functionCode == SrvLocHeader.AttrRqst) {
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 			    return SLPV1SAttrMsg.makeEmptyReply(hdr);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 			}
4130Sstevel@tonic-gate 		    }
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 		} catch (ServiceLocationException exx) {
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 		    hdr.monolingual = true;
4180Sstevel@tonic-gate 		    hdr.makeErrorReply(exx);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 		}
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		// Otherwise, we just ignore it.
4230Sstevel@tonic-gate 	    }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	    // Anything over AUTHENTICATION_FAILED is an internal error in V1.
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	    if (hdr.errCode > ServiceLocationException.AUTHENTICATION_FAILED) {
4280Sstevel@tonic-gate 		hdr.errCode = ServiceLocationException.PARSE_ERROR;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	    }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	} else if (ex instanceof IllegalArgumentException ||
4330Sstevel@tonic-gate 		   ex instanceof IOException) {
4340Sstevel@tonic-gate 	    hdr.errCode = ServiceLocationException.PARSE_ERROR;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	} else {
4370Sstevel@tonic-gate 	    hdr.errCode = ServiceLocationException.PARSE_ERROR;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	// Construct header description.
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	hdr.constructDescription("SrvLocMsg", "");
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	return hdr;
4460Sstevel@tonic-gate     }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate     // Return a reply header with flags properly set.
4490Sstevel@tonic-gate 
makeReplyHeader()4500Sstevel@tonic-gate     SLPHeaderV1 makeReplyHeader() {
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	SLPHeaderV1 hdr = null;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	try {
4550Sstevel@tonic-gate 	    hdr = (SLPHeaderV1)this.clone();
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	} catch (CloneNotSupportedException ex) {
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	    // We know that we support it.
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	hdr.functionCode = replyFunctionCode;
4630Sstevel@tonic-gate 	hdr.length = 0;
4640Sstevel@tonic-gate 	hdr.previousResponders = null;
4650Sstevel@tonic-gate 	hdr.scopes = null;
4660Sstevel@tonic-gate 	hdr.overflow = false;
4670Sstevel@tonic-gate 	hdr.fresh = false;
4680Sstevel@tonic-gate 	hdr.mcast = false;
4690Sstevel@tonic-gate 	hdr.nbytes = 0;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	return hdr;
4720Sstevel@tonic-gate     }
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate     // Return display string.
4750Sstevel@tonic-gate 
toString()4760Sstevel@tonic-gate     public String toString() {
4770Sstevel@tonic-gate 	return
4780Sstevel@tonic-gate 	    getMsgType() + ":version=``" + version + "''\n" +
4790Sstevel@tonic-gate 	    "       functionCode=``" + functionCode + "''\n" +
4800Sstevel@tonic-gate 	    "       length=``" + length + "''\n" +
4810Sstevel@tonic-gate 	    "       overflow=``" + overflow + "''\n" +
4820Sstevel@tonic-gate 	    "       mcast = ``" + mcast + "''\n" +
4830Sstevel@tonic-gate 	    "       fresh=``" + fresh + "''\n" +
4840Sstevel@tonic-gate 	    "       monolingual=``" + monolingual + "''\n" +
4850Sstevel@tonic-gate 	    "       charCode=``" + charCode + "''\n" +
4860Sstevel@tonic-gate 	    "       locale = ``" + locale + "''\n" +
4870Sstevel@tonic-gate 	    "       xid=``0x" + Integer.toHexString(xid) + "''\n" +
4880Sstevel@tonic-gate 	    "       errCode=``" + errCode + "''\n" +
4890Sstevel@tonic-gate 	    "       previousResponders=``" + previousResponders + "''\n" +
4900Sstevel@tonic-gate 	    "       scopes=``" + scopes + "''\n" +
4910Sstevel@tonic-gate 	    getMsgDescription();
4920Sstevel@tonic-gate     }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate     //
4950Sstevel@tonic-gate     // Validation Utilities.
4960Sstevel@tonic-gate     //
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate     /**
4990Sstevel@tonic-gate      * Validate the scope name to be sure it doesn't contain forbidden
5000Sstevel@tonic-gate      * chars and isn't one of the reserved scope names.
5010Sstevel@tonic-gate      */
5020Sstevel@tonic-gate 
validateScope(String scope)5030Sstevel@tonic-gate     static void validateScope(String scope)
5040Sstevel@tonic-gate 	throws ServiceLocationException
5050Sstevel@tonic-gate     {
5060Sstevel@tonic-gate 	if (scope.indexOf('/') != -1 || scope.indexOf(',') != -1 ||
5070Sstevel@tonic-gate 	    scope.indexOf(':') != -1) {
5080Sstevel@tonic-gate 	    throw new ServiceLocationException(
5090Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5100Sstevel@tonic-gate 				"v1_scope_char_res",
5110Sstevel@tonic-gate 				new Object[] {scope});
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	// Check against reserved scope names.
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	if (scope.equalsIgnoreCase("local") ||
5170Sstevel@tonic-gate 	    scope.equalsIgnoreCase("remote")) {
5180Sstevel@tonic-gate 	    throw new ServiceLocationException(
5190Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5200Sstevel@tonic-gate 				"v1_scope_name_res",
5210Sstevel@tonic-gate 				new Object[] {scope});
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate     }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate     /**
5270Sstevel@tonic-gate      * Remove IANA from the service type name.
5280Sstevel@tonic-gate      *
5290Sstevel@tonic-gate      * @param serviceType The service type and naming authority.
5300Sstevel@tonic-gate      * @return The service type name with IANA removed.
5310Sstevel@tonic-gate      */
5320Sstevel@tonic-gate 
removeIANA(String serviceType)5330Sstevel@tonic-gate     static String removeIANA(String serviceType) {
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	// Substitute null string for IANA.
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	int idx = 0;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	serviceType = serviceType.toLowerCase();
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if ((idx = serviceType.indexOf("." + ServiceType.IANA)) != -1) {
5420Sstevel@tonic-gate 	    serviceType = serviceType.substring(0, idx);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	return serviceType;
5470Sstevel@tonic-gate     }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate     // Check whether this is a vaild SLPv1 service type. Also remove
5500Sstevel@tonic-gate     //  IANA.
5510Sstevel@tonic-gate 
checkServiceType(String stype)5520Sstevel@tonic-gate     static String checkServiceType(String stype)
5530Sstevel@tonic-gate 	throws ServiceLocationException {
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	// Check for trailing colon and remove it.
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	if (!stype.endsWith(":")) {
5580Sstevel@tonic-gate 	    throw
5590Sstevel@tonic-gate 		new ServiceLocationException(
5600Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5610Sstevel@tonic-gate 				"v1_service_type_format",
5620Sstevel@tonic-gate 				new Object[] {stype});
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	String type = stype.substring(0, stype.length()-1);
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	// Remove IANA.
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	type = removeIANA(type);
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	// Check syntax.
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	ServiceType st = new ServiceType(type);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	// Reject if abstract type. SLPv1 doesn't handle
5770Sstevel@tonic-gate 	//  abstract types.
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	if (st.isAbstractType()) {
5800Sstevel@tonic-gate 	    throw
5810Sstevel@tonic-gate 		new ServiceLocationException(
5820Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5830Sstevel@tonic-gate 				"v1_abstract_type",
5840Sstevel@tonic-gate 				new Object[0]);
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	// Reject if not a service: type. SLPv1 doesn't handle
5890Sstevel@tonic-gate 	//  nonservice: types.
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	if (!st.isServiceURL()) {
5920Sstevel@tonic-gate 	    throw
5930Sstevel@tonic-gate 		new ServiceLocationException(
5940Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5950Sstevel@tonic-gate 				"v1_not_surl",
5960Sstevel@tonic-gate 				new Object[0]);
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	return type;
6010Sstevel@tonic-gate     }
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate     //
6040Sstevel@tonic-gate     // Parsing Utilities.
6050Sstevel@tonic-gate     //
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate     // Parse string, bump byte count.
6080Sstevel@tonic-gate 
getString(StringBuffer buf, DataInputStream dis)6090Sstevel@tonic-gate     byte[] getString(StringBuffer buf, DataInputStream dis)
6100Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	int i, n = 0;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	// Get length.
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	n = getInteger(dis);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	byte[] bytes = new byte[n];
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	// Read bytes.
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	dis.readFully(bytes, 0, n);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	// If the encoding type is Unicode, then figure out first
6250Sstevel@tonic-gate 	//  whether it's big or little endian from byte header. Future
6260Sstevel@tonic-gate 	//  calls won't have to go through this grief unless the byte header
6270Sstevel@tonic-gate 	//  is missing.
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	if (this.charCode == IANACharCode.UNICODE) {
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	    this.charCode = IANACharCode.getUnicodeEndianess(bytes);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	String charCode = this.charCode;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	// If we are still just Unicode by this point, then we need to
6380Sstevel@tonic-gate 	//  add the big endian bytes to the beginning of the array.
6390Sstevel@tonic-gate 	//  Otherwise, Java won't parse it. Note that we don't change
6400Sstevel@tonic-gate 	//  the flag in the header, since we will need to convert the
6410Sstevel@tonic-gate 	//  next time around as well.
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	if (charCode == IANACharCode.UNICODE) {
6440Sstevel@tonic-gate 	    charCode = IANACharCode.UNICODE_BIG;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	    bytes = IANACharCode.addBigEndianFlag(bytes);
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	// Convert the bytes into a string.
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	buf.setLength(0);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	buf.append(getBytesString(bytes, charCode));
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	return bytes;
6570Sstevel@tonic-gate     }
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate     // Parse out string, bump byte count. Use header encoding.
6600Sstevel@tonic-gate 
putString(String string, ByteArrayOutputStream baos)6610Sstevel@tonic-gate     byte[] putString(String string, ByteArrayOutputStream baos) {
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	// If the charCode is UNICODE, arbirtarily change to big or little,
6640Sstevel@tonic-gate 	//  while Java will parse.
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	if (charCode == IANACharCode.UNICODE) {
6670Sstevel@tonic-gate 	    charCode = IANACharCode.UNICODE_BIG;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	byte[] bytes = putStringField(string, baos, charCode);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	nbytes += bytes.length;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	return bytes;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate     }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate     // Parse in a service URL including lifetime if necessary.
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate     protected ServiceURL
parseServiceURLIn(DataInputStream dis, boolean lifeTimeToo, short errCode)6820Sstevel@tonic-gate 	parseServiceURLIn(DataInputStream dis,
6830Sstevel@tonic-gate 			  boolean lifeTimeToo,
6840Sstevel@tonic-gate 			  short errCode)
6850Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	int lifetime = 0;
6880Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	if (lifeTimeToo) {
6910Sstevel@tonic-gate 	    lifetime = getInt(dis);
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	getString(buf, dis);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	ServiceURL url = null;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	try {
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	    url = new ServiceURLV1(buf.toString(), lifetime);
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	} catch (IllegalArgumentException ex) {
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	    throw
7050Sstevel@tonic-gate 		new ServiceLocationException(errCode,
7060Sstevel@tonic-gate 					     "malformed_url",
7070Sstevel@tonic-gate 					     new Object[] {ex});
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	return url;
7110Sstevel@tonic-gate     }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate     // Parse out a service URL including lifetime if required.
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate     void
parseServiceURLOut(ServiceURL surl, boolean lifetimeToo, ByteArrayOutputStream baos)7160Sstevel@tonic-gate 	parseServiceURLOut(ServiceURL surl,
7170Sstevel@tonic-gate 			   boolean lifetimeToo,
7180Sstevel@tonic-gate 			   ByteArrayOutputStream baos)
7190Sstevel@tonic-gate 	throws ServiceLocationException {
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	String ssurl = surl.toString();
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (lifetimeToo) {
7240Sstevel@tonic-gate 	    putInt(surl.getLifetime(), baos);
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	putString(ssurl, baos);
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate     }
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate     // Parse in a list of attributes, returing a vector of
7320Sstevel@tonic-gate     //  ServiceLocationAttribute objects.
7330Sstevel@tonic-gate 
parseAttributeVectorIn(DataInputStream dis)7340Sstevel@tonic-gate     protected Vector parseAttributeVectorIn(DataInputStream dis)
7350Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	getString(buf, dis);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	SLPConfig config = SLPConfig.getSLPConfig();
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	// Parse the list into ServiceLocationAttribute objects.
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	Vector attrForms = parseCommaSeparatedListIn(buf.toString(), false);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	int i, n = attrForms.size();
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
7500Sstevel@tonic-gate 	    String attrForm =
7510Sstevel@tonic-gate 		(String)attrForms.elementAt(i);
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	    attrForms.setElementAt(new ServiceLocationAttributeV1(attrForm,
7540Sstevel@tonic-gate 								  charCode,
7550Sstevel@tonic-gate 								  false),
7560Sstevel@tonic-gate 				   i);
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	return attrForms;
7600Sstevel@tonic-gate     }
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate     // Parse out a V1 attribute vector.
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate     void
parseAttributeVectorOut(Vector attrs, ByteArrayOutputStream baos)7650Sstevel@tonic-gate 	parseAttributeVectorOut(Vector attrs,
7660Sstevel@tonic-gate 				ByteArrayOutputStream baos)
7670Sstevel@tonic-gate 	throws ServiceLocationException {
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	Enumeration en = attrs.elements();
7700Sstevel@tonic-gate 	Vector strings = new Vector();
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	// Convert the attributes to strings, escaping characters to
7730Sstevel@tonic-gate 	//  escape.
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	while (en.hasMoreElements()) {
7760Sstevel@tonic-gate 	    ServiceLocationAttribute attr =
7770Sstevel@tonic-gate 		(ServiceLocationAttribute)en.nextElement();
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	    // Make an SLPv1 attribute out of it, so we can
7800Sstevel@tonic-gate 	    //  externalize it with the v1 encoding scheme.
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	    ServiceLocationAttributeV1 attrv1 =
7830Sstevel@tonic-gate 		new ServiceLocationAttributeV1(attr);
7840Sstevel@tonic-gate 	    attrv1.charCode = charCode;
7850Sstevel@tonic-gate 	    String out = attrv1.externalize();
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	    strings.addElement(out);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	}
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	// Parse it out.
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	parseCommaSeparatedListOut(strings, baos);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate     }
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate     // Parse in previous responders.
7980Sstevel@tonic-gate 
parsePreviousRespondersIn(DataInputStream dis)7990Sstevel@tonic-gate     void parsePreviousRespondersIn(DataInputStream dis)
8000Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	getString(buf, dis);
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	previousResponders =
8070Sstevel@tonic-gate 	    parseCommaSeparatedListIn(buf.toString(), true);
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate     }
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate     // Put out a vector of strings.
8120Sstevel@tonic-gate 
putStringVector(Vector v, ByteArrayOutputStream baos)8130Sstevel@tonic-gate     void putStringVector(Vector v, ByteArrayOutputStream baos) {
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	int i, n = v.size();
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	// Put out the total number of strings.
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	putInt(n, baos);
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	// Put out the strings.
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	    putString((String)v.elementAt(i), baos);
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate     }
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate     // Return an SLPv1 DAAdvert.
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate     SDAAdvert
getDAAdvert(short xid, long timestamp, ServiceURL url, Vector scopes, Vector attrs)8320Sstevel@tonic-gate 	getDAAdvert(short xid,
8330Sstevel@tonic-gate 		    long timestamp,
8340Sstevel@tonic-gate 		    ServiceURL url,
8350Sstevel@tonic-gate 		    Vector scopes,
8360Sstevel@tonic-gate 		    Vector attrs)
8370Sstevel@tonic-gate 	throws ServiceLocationException {
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	// If scopes vector is null, then return all scopes for this
8400Sstevel@tonic-gate 	//  DA.
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	if (scopes.size() <= 0) {
8430Sstevel@tonic-gate 	    scopes = SLPConfig.getSLPConfig().getSAConfiguredScopes();
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	return new SLPV1SDAAdvert(this, xid, timestamp, url, scopes, attrs);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate     }
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate     // Reimplement clone() to get the header size right.
8520Sstevel@tonic-gate 
clone()8530Sstevel@tonic-gate     public Object clone()
8540Sstevel@tonic-gate 	throws CloneNotSupportedException {
8550Sstevel@tonic-gate 	SLPHeaderV1 hdr = (SLPHeaderV1)super.clone();
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	hdr.nbytes = HEADER_BYTES + 2;  // for error code...
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	return hdr;
8600Sstevel@tonic-gate     }
8610Sstevel@tonic-gate }
862