xref: /illumos-gate/usr/src/lib/libslp/javalib/com/sun/slp/Transact.java (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * ident	"%Z%%M%	%I%	%E% SMI"
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright 1999-2002 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate //  Transact.java:    Low level details of performing an SLP
31*7c478bd9Sstevel@tonic-gate //                    network transaction.
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate package com.sun.slp;
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate import java.util.*;
36*7c478bd9Sstevel@tonic-gate import java.net.*;
37*7c478bd9Sstevel@tonic-gate import java.io.*;
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate /**
40*7c478bd9Sstevel@tonic-gate  * Transact performs the low level details for transacting an SLP network
41*7c478bd9Sstevel@tonic-gate  * query. Note that, in the future, this class may spin separate threads
42*7c478bd9Sstevel@tonic-gate  * for DA requests as well.
43*7c478bd9Sstevel@tonic-gate  */
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate class Transact extends Object implements Runnable {
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate     // Cache of open TCP sockets.
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate     private static final Hashtable TCPSocketCache = new Hashtable();
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate     // SLP config object.
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate     protected static SLPConfig config = null;
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate     // Message to send.
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate     protected SrvLocMsg msgOut = null;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate     // Vector of return values.
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate     protected Vector returns = null;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate     // Timeout for multicast convergence. Varies if it's DA discovery or
64*7c478bd9Sstevel@tonic-gate     //  request multicast.
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate     protected int[] MSTimeouts;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate     // Maximum results desired for multicast.
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate     protected int maxResults = 0;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate     // Exception to throw.
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate     protected ServiceLocationException exErr = null;
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate     // Multicast address to use.
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate     protected InetAddress address = null;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate     // If this is true, continue multicast after the first set of stuff
81*7c478bd9Sstevel@tonic-gate     //  is found. Exit when three tries have happened without finding
82*7c478bd9Sstevel@tonic-gate     //  anything.
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate     boolean continueAfterFound = false;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate     /**
87*7c478bd9Sstevel@tonic-gate      * Perform a query to the SLP network. The multicast query is performed
88*7c478bd9Sstevel@tonic-gate      * in a separate thread for performance reasons. DAs having the
89*7c478bd9Sstevel@tonic-gate      * same scope set are queried until one answers. These DAs form
90*7c478bd9Sstevel@tonic-gate      * an equivalence class.
91*7c478bd9Sstevel@tonic-gate      *
92*7c478bd9Sstevel@tonic-gate      * @param daEquivClasses Vector of DATable.DARecord objects in the
93*7c478bd9Sstevel@tonic-gate      *			  same equivalence clase w.r.t. scopes.
94*7c478bd9Sstevel@tonic-gate      * @param uniMsg A unicast message to send.
95*7c478bd9Sstevel@tonic-gate      * @param multiMsg A multicast message to send.
96*7c478bd9Sstevel@tonic-gate      * @param address Multicast address to use.
97*7c478bd9Sstevel@tonic-gate      * @return Vector of SrvLocMsg objects with results.
98*7c478bd9Sstevel@tonic-gate      */
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate     static Vector
transactUA(Vector daEquivClasses, SrvLocMsg uniMsg, SrvLocMsg multiMsg, InetAddress address)101*7c478bd9Sstevel@tonic-gate 	transactUA(Vector daEquivClasses,
102*7c478bd9Sstevel@tonic-gate 		   SrvLocMsg uniMsg,
103*7c478bd9Sstevel@tonic-gate 		   SrvLocMsg multiMsg,
104*7c478bd9Sstevel@tonic-gate 		   InetAddress address)
105*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	// If we need to multicast, then start the multicast thread.
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	Vector ret = new Vector();
110*7c478bd9Sstevel@tonic-gate 	Thread multiThread = null;
111*7c478bd9Sstevel@tonic-gate 	Transact tracon = null;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if (multiMsg != null) {
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	    // Create a new Transact multicast thread.
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate             // The final argument to the constructor of Transact determines
118*7c478bd9Sstevel@tonic-gate             // whether to return after the first result or to continue to
119*7c478bd9Sstevel@tonic-gate             // gather more than one result.  The value to this field
120*7c478bd9Sstevel@tonic-gate             // continueAfterFound MUST be set to 'true' or else multicast
121*7c478bd9Sstevel@tonic-gate             // based discovery will find the first result, not all results,
122*7c478bd9Sstevel@tonic-gate             // as it should.
123*7c478bd9Sstevel@tonic-gate 	    tracon =
124*7c478bd9Sstevel@tonic-gate 		new Transact(multiMsg,
125*7c478bd9Sstevel@tonic-gate 			     ret,
126*7c478bd9Sstevel@tonic-gate 			     config.getMulticastTimeouts(),
127*7c478bd9Sstevel@tonic-gate 			     config.getMaximumResults(),
128*7c478bd9Sstevel@tonic-gate 			     address,
129*7c478bd9Sstevel@tonic-gate 			     true);  // continueAfterFound
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	    multiThread = new Thread(tracon);
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	    // Run it.
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	    multiThread.start();
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	}
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	// Go through the msgTable doing all the DAs.
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	ServiceLocationException exx = null;
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	if (daEquivClasses != null) {
144*7c478bd9Sstevel@tonic-gate 	    exx =
145*7c478bd9Sstevel@tonic-gate 		transactUnicastMsg(daEquivClasses,
146*7c478bd9Sstevel@tonic-gate 				   uniMsg,
147*7c478bd9Sstevel@tonic-gate 				   ret,
148*7c478bd9Sstevel@tonic-gate 				   config.getMaximumResults());
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	// Wait until the TransactConverge thread is done, if necessary.
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	if (multiThread != null) {
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	    try {
157*7c478bd9Sstevel@tonic-gate 		multiThread.join();
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	    } catch (InterruptedException ex) {
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	    }
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	// If there was a problem in either the multicast thread or in
166*7c478bd9Sstevel@tonic-gate 	//  the unicast call, throw an exception, but *only* if no
167*7c478bd9Sstevel@tonic-gate 	//  results came back.
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	if (ret.size() <= 0) {
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	    if (exx != null) {
172*7c478bd9Sstevel@tonic-gate 		short err = exx.getErrorCode();
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 		if (err != ServiceLocationException.VERSION_NOT_SUPPORTED &&
175*7c478bd9Sstevel@tonic-gate 		    err != ServiceLocationException.INTERNAL_ERROR &&
176*7c478bd9Sstevel@tonic-gate 		    err != ServiceLocationException.OPTION_NOT_SUPPORTED &&
177*7c478bd9Sstevel@tonic-gate 		    err != ServiceLocationException.REQUEST_NOT_SUPPORTED) {
178*7c478bd9Sstevel@tonic-gate 		    throw exx;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 		}
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	    }
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	    if (tracon != null && tracon.exErr != null) {
185*7c478bd9Sstevel@tonic-gate 		short err = tracon.exErr.getErrorCode();
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 		if (err != ServiceLocationException.VERSION_NOT_SUPPORTED &&
188*7c478bd9Sstevel@tonic-gate 		    err != ServiceLocationException.INTERNAL_ERROR &&
189*7c478bd9Sstevel@tonic-gate 		    err != ServiceLocationException.OPTION_NOT_SUPPORTED &&
190*7c478bd9Sstevel@tonic-gate 		    err != ServiceLocationException.REQUEST_NOT_SUPPORTED) {
191*7c478bd9Sstevel@tonic-gate 		    throw tracon.exErr;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		}
194*7c478bd9Sstevel@tonic-gate 	    }
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	// Return the result to the client.
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	return ret;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate     }
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate     /**
205*7c478bd9Sstevel@tonic-gate      * Transact a message with DAs. Put the returned SrvLocMsg
206*7c478bd9Sstevel@tonic-gate      * object into the Vector ret.
207*7c478bd9Sstevel@tonic-gate      *
208*7c478bd9Sstevel@tonic-gate      * @param daEquivClasses Vector of DATable.DARecord objects in the
209*7c478bd9Sstevel@tonic-gate      *			   same equivalence clase w.r.t. scopes.
210*7c478bd9Sstevel@tonic-gate      * @param msg SrvLocMsg Message to send.
211*7c478bd9Sstevel@tonic-gate      * @param ret Vector for returns.
212*7c478bd9Sstevel@tonic-gate      * @param maxResults Maximum results expected.
213*7c478bd9Sstevel@tonic-gate      * @return A ServiceLocationException object if an exception occured.
214*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException
215*7c478bd9Sstevel@tonic-gate      *            If results cannot be obtained in the timeout interval
216*7c478bd9Sstevel@tonic-gate      *            specified in the 'config.' or
217*7c478bd9Sstevel@tonic-gate      *            If networking resources cannot be obtained or used
218*7c478bd9Sstevel@tonic-gate      *            effectively.
219*7c478bd9Sstevel@tonic-gate      */
220*7c478bd9Sstevel@tonic-gate     static ServiceLocationException
transactUnicastMsg(Vector daEquivClasses, SrvLocMsg msg, Vector ret, int maxResults)221*7c478bd9Sstevel@tonic-gate 	transactUnicastMsg(Vector daEquivClasses,
222*7c478bd9Sstevel@tonic-gate 			   SrvLocMsg msg,
223*7c478bd9Sstevel@tonic-gate 			   Vector ret,
224*7c478bd9Sstevel@tonic-gate 			   int maxResults) {
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	// Get the config object if we need it.
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	if (config == null) {
229*7c478bd9Sstevel@tonic-gate 	    config = SLPConfig.getSLPConfig();
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	DatagramSocket ds = null;
234*7c478bd9Sstevel@tonic-gate 	int i, n = daEquivClasses.size();
235*7c478bd9Sstevel@tonic-gate 	ServiceLocationException exx = null;
236*7c478bd9Sstevel@tonic-gate 	InetAddress addr = null;
237*7c478bd9Sstevel@tonic-gate 	int numReplies = 0;
238*7c478bd9Sstevel@tonic-gate 	DATable daTable = DATable.getDATable();
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	try {
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	    // Go through the DA address equivalence classes we need
243*7c478bd9Sstevel@tonic-gate 	    //  to query.
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	    for (i = 0; i < n && numReplies < maxResults; i++) {
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 		DATable.DARecord rec =
248*7c478bd9Sstevel@tonic-gate 		    (DATable.DARecord)daEquivClasses.elementAt(i);
249*7c478bd9Sstevel@tonic-gate 		Vector daAddresses = (Vector)rec.daAddresses.clone();
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 		// Get a new outgoing socket.
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 		if (ds == null) {
254*7c478bd9Sstevel@tonic-gate 		    ds = new DatagramSocket();
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 		}
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 		// Go through the DA addresses until we get a reply from one.
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 		Enumeration en = daAddresses.elements();
261*7c478bd9Sstevel@tonic-gate 		SrvLocHeader mhdr = msg.getHeader();
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 		while (en.hasMoreElements()) {
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 		    try {
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 			addr = (InetAddress)en.nextElement();
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 			if (config.traceDATraffic()) {
270*7c478bd9Sstevel@tonic-gate 			    config.writeLog("sending_da_trace",
271*7c478bd9Sstevel@tonic-gate 					    new Object[] {
272*7c478bd9Sstevel@tonic-gate 				Integer.toHexString(mhdr.xid),
273*7c478bd9Sstevel@tonic-gate 				    addr});
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 			}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 			// Get the reply message if any.
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 			SrvLocMsg rply = transactDatagramMsg(ds, addr, msg);
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 			if (!filterRply(msg, rply, addr)) {
282*7c478bd9Sstevel@tonic-gate 			    continue;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 			}
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 			SrvLocHeader rhdr = rply.getHeader();
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 			if (config.traceDATraffic()) {
289*7c478bd9Sstevel@tonic-gate 			    config.writeLog("reply_da_trace",
290*7c478bd9Sstevel@tonic-gate 					    new Object[] {
291*7c478bd9Sstevel@tonic-gate 				Integer.toHexString(rhdr.xid),
292*7c478bd9Sstevel@tonic-gate 				    addr});
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 			}
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 			// If overflow, try TCP.
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 			if (rhdr.overflow) {
299*7c478bd9Sstevel@tonic-gate 			    if (config.traceDATraffic()) {
300*7c478bd9Sstevel@tonic-gate 				config.writeLog("tcp_send_da_trace",
301*7c478bd9Sstevel@tonic-gate 						new Object[] {
302*7c478bd9Sstevel@tonic-gate 				    Integer.toHexString(mhdr.xid),
303*7c478bd9Sstevel@tonic-gate 					addr});
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 			    }
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 			    rply = transactTCPMsg(addr, msg, false);
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 			    if (config.traceDATraffic()) {
310*7c478bd9Sstevel@tonic-gate 				config.writeLog("tcp_reply_da_trace",
311*7c478bd9Sstevel@tonic-gate 						new Object[] {
312*7c478bd9Sstevel@tonic-gate 				    (msg == null ? "<null>":
313*7c478bd9Sstevel@tonic-gate 				     Integer.toHexString(mhdr.xid)),
314*7c478bd9Sstevel@tonic-gate 					addr});
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 			    }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 			    if (rply == null) {
319*7c478bd9Sstevel@tonic-gate 				continue;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 			    }
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 			}
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 			// Increment number of replies we received.
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 			SrvLocHeader hdr = rply.getHeader();
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 			numReplies += hdr.iNumReplies;
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 			// Add to return vector.
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 			ret.addElement(rply);
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 			// Break out of the loop, since we only need one in
336*7c478bd9Sstevel@tonic-gate 			//  this equivalence class.
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 			break;
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 		    } catch (ServiceLocationException ex) {
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 			config.writeLog("da_exception_trace",
343*7c478bd9Sstevel@tonic-gate 					new Object[] {
344*7c478bd9Sstevel@tonic-gate 			    new Short(ex.getErrorCode()),
345*7c478bd9Sstevel@tonic-gate 				addr,
346*7c478bd9Sstevel@tonic-gate 				ex.getMessage()});
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 			// In case we are querying more than one DA, we
349*7c478bd9Sstevel@tonic-gate 			// save th exception, returning it to the caller to
350*7c478bd9Sstevel@tonic-gate 			// decide if it should be thrown. We ignore DA_BUSY,
351*7c478bd9Sstevel@tonic-gate 			// though, since the DA may free up later.
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 			short errCode = ex.getErrorCode();
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 			if (errCode != ServiceLocationException.DA_BUSY) {
356*7c478bd9Sstevel@tonic-gate 			    exx = ex;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 			}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 			// If the error code is NETWORK_TIMED_OUT, then remove
361*7c478bd9Sstevel@tonic-gate 			//  this DA from the DA table. If it's just down
362*7c478bd9Sstevel@tonic-gate 			//  temporarily, we'll get it next time we go to
363*7c478bd9Sstevel@tonic-gate 			//  the server to get the DA addresses.
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 			if (errCode ==
366*7c478bd9Sstevel@tonic-gate 			    ServiceLocationException.NETWORK_TIMED_OUT) {
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 			    if (config.traceDATraffic()) {
369*7c478bd9Sstevel@tonic-gate 				config.writeLog("da_drop",
370*7c478bd9Sstevel@tonic-gate 						new Object[] {
371*7c478bd9Sstevel@tonic-gate 				    addr, rec.scopes});
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 			    }
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 			    daTable.removeDA(addr, rec.scopes);
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 			}
378*7c478bd9Sstevel@tonic-gate 		    }
379*7c478bd9Sstevel@tonic-gate 		}
380*7c478bd9Sstevel@tonic-gate 	    }
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	} catch (SocketException ex) {
383*7c478bd9Sstevel@tonic-gate 	    exx =
384*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
385*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.NETWORK_ERROR,
386*7c478bd9Sstevel@tonic-gate 				"socket_creation_failure",
387*7c478bd9Sstevel@tonic-gate 				new Object[] {addr, ex.getMessage()});
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	} finally {
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	    // Clean up socket.
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	    if (ds != null) {
394*7c478bd9Sstevel@tonic-gate 		ds.close();
395*7c478bd9Sstevel@tonic-gate 	    }
396*7c478bd9Sstevel@tonic-gate 	}
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	return exx;
399*7c478bd9Sstevel@tonic-gate     }
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate     /**
402*7c478bd9Sstevel@tonic-gate      * Transact a message via. UDP. Try a maximum of three times if
403*7c478bd9Sstevel@tonic-gate      * a timeout.
404*7c478bd9Sstevel@tonic-gate      *
405*7c478bd9Sstevel@tonic-gate      * @param ds The datagram socket to use.
406*7c478bd9Sstevel@tonic-gate      * @param addr The DA to contact.
407*7c478bd9Sstevel@tonic-gate      * @param msg The message to send.
408*7c478bd9Sstevel@tonic-gate      * @return The SrvLocMsg returned or null if none.
409*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Due to errors in parsing message.
410*7c478bd9Sstevel@tonic-gate      */
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate     static private SrvLocMsg
transactDatagramMsg(DatagramSocket ds, InetAddress addr, SrvLocMsg msg)413*7c478bd9Sstevel@tonic-gate 	transactDatagramMsg(DatagramSocket ds, InetAddress addr, SrvLocMsg msg)
414*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	SrvLocMsg rply = null;
417*7c478bd9Sstevel@tonic-gate 	byte[] outbuf = getBytes(msg, false, false);
418*7c478bd9Sstevel@tonic-gate 	byte[] inbuf = new byte[Defaults.iReadMaxMTU];
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	// Construct the datagram packet to send.
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	DatagramPacket dpReply =
423*7c478bd9Sstevel@tonic-gate 	    new DatagramPacket(inbuf, inbuf.length);
424*7c478bd9Sstevel@tonic-gate 	DatagramPacket dpRequest =
425*7c478bd9Sstevel@tonic-gate 	    new DatagramPacket(outbuf, outbuf.length, addr, Defaults.iSLPPort);
426*7c478bd9Sstevel@tonic-gate 	int[] timeouts = config.getDatagramTimeouts();
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	// Resend for number of timeouts in timeout interval.
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	int i;
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < timeouts.length; i++) {
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	    // Catch timeout and IO errors.
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	    try {
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 		ds.setSoTimeout(timeouts[i]);
439*7c478bd9Sstevel@tonic-gate 		ds.send(dpRequest);
440*7c478bd9Sstevel@tonic-gate 		ds.receive(dpReply);
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 		// Process result into a reply object.
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		DataInputStream dis =
445*7c478bd9Sstevel@tonic-gate 		    new DataInputStream(
446*7c478bd9Sstevel@tonic-gate 			new ByteArrayInputStream(dpReply.getData()));
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 		rply = internalize(dis, addr);
449*7c478bd9Sstevel@tonic-gate 		break;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	    } catch (InterruptedIOException ex) {
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		// Did not get it on the first timeout, try again.
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 		if (config.traceDrop()|| config.traceDATraffic()) {
456*7c478bd9Sstevel@tonic-gate 		    config.writeLog("udp_timeout",
457*7c478bd9Sstevel@tonic-gate 				    new Object[] {addr});
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 		}
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 		continue;
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	    } catch (IOException ex) {
464*7c478bd9Sstevel@tonic-gate 		Object[] message = {addr, ex.getMessage()};
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 		if (config.traceDrop() || config.traceDATraffic()) {
467*7c478bd9Sstevel@tonic-gate 		    config.writeLog("datagram_io_error",
468*7c478bd9Sstevel@tonic-gate 				    message);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		}
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 		throw
473*7c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
474*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.NETWORK_ERROR,
475*7c478bd9Sstevel@tonic-gate 				"datagram_io_error",
476*7c478bd9Sstevel@tonic-gate 				message);
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	    }
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	// If nothing, then we've timed out. DAs with no matching
482*7c478bd9Sstevel@tonic-gate 	//  info should at least return a reply.
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	if (rply == null) {
485*7c478bd9Sstevel@tonic-gate 	    throw
486*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
487*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.NETWORK_TIMED_OUT,
488*7c478bd9Sstevel@tonic-gate 				"udp_timeout",
489*7c478bd9Sstevel@tonic-gate 				new Object[] {addr});
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	return rply;
494*7c478bd9Sstevel@tonic-gate     }
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate     /**
497*7c478bd9Sstevel@tonic-gate      * Transact a message using TCP, since the reply was too big.
498*7c478bd9Sstevel@tonic-gate      * @parameter addr Address of the DA to contact.
499*7c478bd9Sstevel@tonic-gate      * @parameter msg  The message object to use.
500*7c478bd9Sstevel@tonic-gate      * @parameter cacheIt Cache socket, if new.
501*7c478bd9Sstevel@tonic-gate      * @return  The SrvLocMsg returned if any.
502*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException
503*7c478bd9Sstevel@tonic-gate      *            If results cannot be obtained in the timeout interval
504*7c478bd9Sstevel@tonic-gate      *            specified in the 'config.'
505*7c478bd9Sstevel@tonic-gate      *            If networking resources cannot be obtained or used
506*7c478bd9Sstevel@tonic-gate      *            effectively.
507*7c478bd9Sstevel@tonic-gate      */
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate     static SrvLocMsg
transactTCPMsg(InetAddress addr, SrvLocMsg msg, boolean cacheIt)510*7c478bd9Sstevel@tonic-gate 	transactTCPMsg(InetAddress addr, SrvLocMsg msg, boolean cacheIt)
511*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	// Get the config object if we need it.
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	if (config == null) {
516*7c478bd9Sstevel@tonic-gate 	    config = SLPConfig.getSLPConfig();
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	}
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	SrvLocMsg rply = null;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	try {
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	    // Transact the message, taking care of socket caching.
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	    rply = transactMsg(addr, msg, cacheIt, true);
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	} catch (InterruptedIOException ex) {
529*7c478bd9Sstevel@tonic-gate 	    Object[] message = {addr};
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	    if (config.traceDrop()|| config.traceDATraffic()) {
532*7c478bd9Sstevel@tonic-gate 		config.writeLog("tcp_timeout",
533*7c478bd9Sstevel@tonic-gate 				message);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	    }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	    throw
538*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
539*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.NETWORK_TIMED_OUT,
540*7c478bd9Sstevel@tonic-gate 				"tcp_timeout",
541*7c478bd9Sstevel@tonic-gate 				message);
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
544*7c478bd9Sstevel@tonic-gate 	    Object[] message = {addr, ex.getMessage()};
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	    if (config.traceDrop() || config.traceDATraffic()) {
547*7c478bd9Sstevel@tonic-gate 		config.writeLog("tcp_io_error",
548*7c478bd9Sstevel@tonic-gate 				message);
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	    }
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	    throw
553*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
554*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.NETWORK_ERROR,
555*7c478bd9Sstevel@tonic-gate 				"tcp_io_error",
556*7c478bd9Sstevel@tonic-gate 				message);
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	// Filter reply for nulls, invalid xid.
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	if (!filterRply(msg, rply, addr)) {
563*7c478bd9Sstevel@tonic-gate 	    return null;
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	return rply;
568*7c478bd9Sstevel@tonic-gate     }
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate     // Uncache a socket.
571*7c478bd9Sstevel@tonic-gate 
uncacheSocket(InetAddress addr, Socket s)572*7c478bd9Sstevel@tonic-gate     static private void uncacheSocket(InetAddress addr, Socket s) {
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	try {
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	    s.close();
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	TCPSocketCache.remove(addr);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate     }
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate     // Get a (possibly cached) TCP socket, cache it if cache is on.
587*7c478bd9Sstevel@tonic-gate 
getTCPSocket(InetAddress addr, boolean cacheIt)588*7c478bd9Sstevel@tonic-gate     static private Socket getTCPSocket(InetAddress addr, boolean cacheIt)
589*7c478bd9Sstevel@tonic-gate 	throws IOException {
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	Socket s = null;
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	// We use the cached socket if we've got it.
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	s = (Socket)TCPSocketCache.get(addr);
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	if (s == null) {
598*7c478bd9Sstevel@tonic-gate 	    s = new Socket(addr, Defaults.iSLPPort);
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	    // Set it so the socket will block for fixed timeout.
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	    s.setSoTimeout(config.getTCPTimeout());
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	}
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	// We cache it if we're supposed to.
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	if (cacheIt) {
609*7c478bd9Sstevel@tonic-gate 	    TCPSocketCache.put(addr, s);
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	return s;
614*7c478bd9Sstevel@tonic-gate     }
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate     // Transact the message, using cached socket if necessary. Retry if
617*7c478bd9Sstevel@tonic-gate     //  flag is true.
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate     static private SrvLocMsg
transactMsg(InetAddress addr, SrvLocMsg msg, boolean cacheIt, boolean retry)620*7c478bd9Sstevel@tonic-gate 	transactMsg(InetAddress addr,
621*7c478bd9Sstevel@tonic-gate 		    SrvLocMsg msg,
622*7c478bd9Sstevel@tonic-gate 		    boolean cacheIt,
623*7c478bd9Sstevel@tonic-gate 		    boolean retry)
624*7c478bd9Sstevel@tonic-gate 	throws InterruptedIOException, IOException, ServiceLocationException {
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	Socket s = null;
627*7c478bd9Sstevel@tonic-gate 	byte outbuf[] = getBytes(msg, false, true);
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	try {
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	    s = getTCPSocket(addr, cacheIt);
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	    DataOutputStream dos = new DataOutputStream(s.getOutputStream());
634*7c478bd9Sstevel@tonic-gate 	    DataInputStream dis = new DataInputStream(s.getInputStream());
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	    // In case the server cuts us off...
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	    try {
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 		// Only one thread at a time gets to use this socket, in case
641*7c478bd9Sstevel@tonic-gate 		//  it was cached. Otherwise, we *may* get interleaved i/o.
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 		synchronized (s) {
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 		    // Send the request.
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 		    dos.write(outbuf, 0, outbuf.length);
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 		    // Read reply.
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 		    return internalize(dis, addr);
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	    } catch (IOException ex) {
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 		// Uncache it, get a new one. If that one doesn't work, we're
658*7c478bd9Sstevel@tonic-gate 		//  hosed.
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 		uncacheSocket(addr, s);
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 		s = null;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 		if (!retry) {
665*7c478bd9Sstevel@tonic-gate 		    throw ex;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 		}
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 		// Recursively call ourselves to take care of this, but
670*7c478bd9Sstevel@tonic-gate 		//  don't retry it.
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 		return transactMsg(addr, msg, cacheIt, false);
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	    }
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 	} finally {
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	    if (s != null && !cacheIt) {
679*7c478bd9Sstevel@tonic-gate 		uncacheSocket(addr, s);
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	    }
682*7c478bd9Sstevel@tonic-gate 	}
683*7c478bd9Sstevel@tonic-gate     }
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate     // Externalize the message into bytes.
686*7c478bd9Sstevel@tonic-gate 
getBytes(SrvLocMsg slm, boolean isMulti, boolean isTCP)687*7c478bd9Sstevel@tonic-gate     static protected byte[] getBytes(SrvLocMsg slm,
688*7c478bd9Sstevel@tonic-gate 				     boolean isMulti,
689*7c478bd9Sstevel@tonic-gate 				     boolean isTCP)
690*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	ByteArrayOutputStream baos = new ByteArrayOutputStream();
693*7c478bd9Sstevel@tonic-gate 	SrvLocHeader hdr = slm.getHeader();
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	hdr.externalize(baos, isMulti, isTCP);
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	byte[] outbuf = baos.toByteArray();
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	// Check if it excceds the output buffer length.
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	if (hdr.overflow) {
702*7c478bd9Sstevel@tonic-gate 	    throw
703*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
704*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.BUFFER_OVERFLOW,
705*7c478bd9Sstevel@tonic-gate 				"buffer_overflow",
706*7c478bd9Sstevel@tonic-gate 				new Object[] {
707*7c478bd9Sstevel@tonic-gate 		    new Integer(outbuf.length),
708*7c478bd9Sstevel@tonic-gate 			new Integer(config.getMTU())});
709*7c478bd9Sstevel@tonic-gate 	}
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	return outbuf;
712*7c478bd9Sstevel@tonic-gate     }
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate     // Filter the reply to make sure the xid matches and that it's not null.
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate     static protected boolean
filterRply(SrvLocMsg msg, SrvLocMsg rply, InetAddress addr)717*7c478bd9Sstevel@tonic-gate 	filterRply(SrvLocMsg msg, SrvLocMsg rply, InetAddress addr) {
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 	SrvLocHeader mhdr = msg.getHeader();
720*7c478bd9Sstevel@tonic-gate 	SrvLocHeader rhdr = rply.getHeader();
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	if (rply == null) {
723*7c478bd9Sstevel@tonic-gate 	    if (config.traceDrop()) {
724*7c478bd9Sstevel@tonic-gate 		config.writeLog("reply_unparsable",
725*7c478bd9Sstevel@tonic-gate 				new Object[] {addr});
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	    }
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	    return false;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	// Check for invalid xid.
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	if (mhdr.xid != rhdr.xid) {
736*7c478bd9Sstevel@tonic-gate 	    if (config.traceDrop()) {
737*7c478bd9Sstevel@tonic-gate 		config.writeLog("wrong_xid",
738*7c478bd9Sstevel@tonic-gate 				new Object[] {addr});
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	    }
741*7c478bd9Sstevel@tonic-gate 	    return false;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 	return true;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate     }
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate     /**
749*7c478bd9Sstevel@tonic-gate      * Internalize the byte array in the input stream into a SrvLocMsg
750*7c478bd9Sstevel@tonic-gate      * subclass. It will be an appropriate subclass for the client agent.
751*7c478bd9Sstevel@tonic-gate      * If an exception comes out of this method, it is converted into
752*7c478bd9Sstevel@tonic-gate      * a SrvLocMsg with error code.
753*7c478bd9Sstevel@tonic-gate      *
754*7c478bd9Sstevel@tonic-gate      *
755*7c478bd9Sstevel@tonic-gate      * @param dis The input stream containing the packet.
756*7c478bd9Sstevel@tonic-gate      * @param addr The address of the replying agent (for error reporting).
757*7c478bd9Sstevel@tonic-gate      * @return The right SrvLocMsg subclass appropriate for the Client Agent.
758*7c478bd9Sstevel@tonic-gate      *		If null is returned, the function code wasn't recognized,
759*7c478bd9Sstevel@tonic-gate      *		and so it may be appropriate for another agent.
760*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If the character set was not valid
761*7c478bd9Sstevel@tonic-gate      *		or an error occured during parsing.
762*7c478bd9Sstevel@tonic-gate      * @exception IOException If DataInputStream throws it.
763*7c478bd9Sstevel@tonic-gate      */
764*7c478bd9Sstevel@tonic-gate 
internalize(DataInputStream dis, InetAddress addr)765*7c478bd9Sstevel@tonic-gate     static protected SrvLocMsg internalize(DataInputStream dis,
766*7c478bd9Sstevel@tonic-gate 					   InetAddress addr)
767*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	int ver = 0, fun = 0;
770*7c478bd9Sstevel@tonic-gate 	SrvLocMsg msg = null;
771*7c478bd9Sstevel@tonic-gate 	SrvLocHeader hdr = null;
772*7c478bd9Sstevel@tonic-gate 	byte[] b = new byte[2];
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	try {
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	    dis.readFully(b, 0, 2);
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	    ver = (int) ((char)b[0] & 0XFF);
779*7c478bd9Sstevel@tonic-gate 	    fun = (int) ((char)b[1] & 0XFF);
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	    // Unrecognized version number if header not returned.
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	    if (ver != Defaults.version) {
784*7c478bd9Sstevel@tonic-gate 		throw
785*7c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
786*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.VERSION_NOT_SUPPORTED,
787*7c478bd9Sstevel@tonic-gate 				"version_number_error",
788*7c478bd9Sstevel@tonic-gate 				new Object[] {new Integer(ver)});
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	    }
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	    // Create the header. Note that we only need to create a
793*7c478bd9Sstevel@tonic-gate 	    //  client side header here, because that is all that
794*7c478bd9Sstevel@tonic-gate 	    //  will be expected by the client side code. Note that we
795*7c478bd9Sstevel@tonic-gate 	    //  *can't* use the SrvLocHeader.newInstance() mechanism
796*7c478bd9Sstevel@tonic-gate 	    //  because Transact lives in the server as well, and
797*7c478bd9Sstevel@tonic-gate 	    //  SrvLocHeader can only handle one header class per
798*7c478bd9Sstevel@tonic-gate 	    //  version.
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	    hdr = new SLPHeaderV2();
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	    // Parse header.
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	    hdr.parseHeader(fun, dis);
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	    // Parse body.
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 	    if ((msg = hdr.parseMsg(dis)) != null) {
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 		// Parse options, if any.
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 		hdr.parseOptions(dis);
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	    }
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	} catch (IllegalArgumentException ex) {
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 	    // During parsing, this can be thrown if syntax errors occur.
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	    throw
821*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
822*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
823*7c478bd9Sstevel@tonic-gate 				"passthrough_addr",
824*7c478bd9Sstevel@tonic-gate 				new Object[] {ex.getMessage(), addr});
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	    // If version code is zero, then we suspect a network error,
829*7c478bd9Sstevel@tonic-gate 	    //  otherwise, it is probably a parse error.
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 	    String fcode = (fun == 0 ? "???":Integer.toString(fun));
832*7c478bd9Sstevel@tonic-gate 	    short exCode =
833*7c478bd9Sstevel@tonic-gate 		(ver == 0 ? ServiceLocationException.NETWORK_ERROR:
834*7c478bd9Sstevel@tonic-gate 		 ServiceLocationException.PARSE_ERROR);
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 	    // During parsing, this can be thrown if the message stream
837*7c478bd9Sstevel@tonic-gate 	    //  is improperly formatted.
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	    throw
840*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(exCode,
841*7c478bd9Sstevel@tonic-gate 					     "ioexception_parsing",
842*7c478bd9Sstevel@tonic-gate 					     new Object[] {
843*7c478bd9Sstevel@tonic-gate 		    ex, fcode, addr, ex.getMessage()});
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	    // Add the address of the replying agent.
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	    throw
850*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(ex.getErrorCode(),
851*7c478bd9Sstevel@tonic-gate 					     "passthrough_addr",
852*7c478bd9Sstevel@tonic-gate 					     new Object[] {
853*7c478bd9Sstevel@tonic-gate 		    ex.getMessage(), addr});
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	}
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	return msg;
858*7c478bd9Sstevel@tonic-gate     }
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate     // Send out the message.
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate     static protected void
send(DatagramSocket ds, SrvLocMsg msg, InetAddress addr)863*7c478bd9Sstevel@tonic-gate 	send(DatagramSocket ds, SrvLocMsg msg, InetAddress addr)
864*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	byte[] outbuf = getBytes(msg, true, false);
867*7c478bd9Sstevel@tonic-gate 	DatagramPacket dpsend =
868*7c478bd9Sstevel@tonic-gate 	    new DatagramPacket(outbuf, outbuf.length, addr, Defaults.iSLPPort);
869*7c478bd9Sstevel@tonic-gate 	ds.send(dpsend);
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate     }
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate     // Check the response and add the previous responder if it is OK.
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate     static protected boolean
addPreviousResponder(SrvLocMsg msg, InetAddress addr)876*7c478bd9Sstevel@tonic-gate 	addPreviousResponder(SrvLocMsg msg, InetAddress addr) {
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	// Add incoming result to the vector.
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	SrvLocHeader hdr = msg.getHeader();
881*7c478bd9Sstevel@tonic-gate 	Vector v = hdr.previousResponders;
882*7c478bd9Sstevel@tonic-gate 	String srcAddr = addr.getHostAddress();
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	if (v.contains(srcAddr)) {	// the SRC ignored its PR list
885*7c478bd9Sstevel@tonic-gate 	    if (config.traceDrop()) {
886*7c478bd9Sstevel@tonic-gate 		config.writeLog("drop_pr",
887*7c478bd9Sstevel@tonic-gate 				new Object[] {
888*7c478bd9Sstevel@tonic-gate 		    srcAddr,
889*7c478bd9Sstevel@tonic-gate 			Integer.toHexString(hdr.xid)});
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	    }
892*7c478bd9Sstevel@tonic-gate 	    return false;
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	} else {
895*7c478bd9Sstevel@tonic-gate 	    hdr.addPreviousResponder(addr);
896*7c478bd9Sstevel@tonic-gate 	    return true;
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 	}
899*7c478bd9Sstevel@tonic-gate     }
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate     // Transact an active request for DA or SA adverts.
902*7c478bd9Sstevel@tonic-gate 
transactActiveAdvertRequest(ServiceType type, SrvLocMsg rqst, ServerDATable daTable)903*7c478bd9Sstevel@tonic-gate     static Vector transactActiveAdvertRequest(ServiceType type,
904*7c478bd9Sstevel@tonic-gate 					      SrvLocMsg rqst,
905*7c478bd9Sstevel@tonic-gate 					      ServerDATable daTable)
906*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	// Perform active advertisement.
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 	Vector ret = new Vector();
911*7c478bd9Sstevel@tonic-gate 	Vector results = new Vector();
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	// Create Transact object and start.
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 	Transact tran = new Transact(rqst,
916*7c478bd9Sstevel@tonic-gate 				     results,
917*7c478bd9Sstevel@tonic-gate 				     config.getMulticastTimeouts(),
918*7c478bd9Sstevel@tonic-gate 				     Integer.MAX_VALUE, // config doesn't apply
919*7c478bd9Sstevel@tonic-gate 				     config.getMulticastAddress(),
920*7c478bd9Sstevel@tonic-gate 				     true);
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	Thread multiThread = new Thread(tran);
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 	multiThread.start();
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	// Wait until the TransactConverge thread is done, if necessary.
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	try {
929*7c478bd9Sstevel@tonic-gate 	    multiThread.join();
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 	} catch (InterruptedException ex) {
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 	}
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 	ServiceLocationException ex = tran.exErr;
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	// Report error.
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	if (ex != null && config.traceDATraffic()) {
940*7c478bd9Sstevel@tonic-gate 	    config.writeLog("sdat_active_err",
941*7c478bd9Sstevel@tonic-gate 			    new Object[] {new Integer(ex.getErrorCode()),
942*7c478bd9Sstevel@tonic-gate 					      ex.getMessage()});
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	    throw ex;
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	}
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	// Process the results.
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	int i, n = results.size();
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
953*7c478bd9Sstevel@tonic-gate 	    Object msg = results.elementAt(i);
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	    if ((type.equals(Defaults.DA_SERVICE_TYPE) &&
956*7c478bd9Sstevel@tonic-gate 		!(msg instanceof CDAAdvert)) ||
957*7c478bd9Sstevel@tonic-gate 		(type.equals(Defaults.SA_SERVICE_TYPE) &&
958*7c478bd9Sstevel@tonic-gate 		!(msg instanceof CSAAdvert))) {
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 		if (config.traceDrop()) {
961*7c478bd9Sstevel@tonic-gate 		    config.writeLog("sdat_nonadvert_err",
962*7c478bd9Sstevel@tonic-gate 				    new Object[] {
963*7c478bd9Sstevel@tonic-gate 			msg});
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 		}
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 		continue;
968*7c478bd9Sstevel@tonic-gate 	    }
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	    // Let DA table handle it if it`s a DAAdvert.
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	    if (type.equals(Defaults.DA_SERVICE_TYPE)) {
973*7c478bd9Sstevel@tonic-gate 		CDAAdvert advert = (CDAAdvert)msg;
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 		daTable.handleAdvertIn(advert);
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	    } else {
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 		// Add scopes from the SAAdvert if not already there.
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 		SrvLocHeader hdr = ((SrvLocMsg)msg).getHeader();
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 		int j, m = hdr.scopes.size();
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < m; j++) {
986*7c478bd9Sstevel@tonic-gate 		    Object o = hdr.scopes.elementAt(j);
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 		    if (!ret.contains(o)) {
989*7c478bd9Sstevel@tonic-gate 			ret.addElement(o);
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 		    }
992*7c478bd9Sstevel@tonic-gate 		}
993*7c478bd9Sstevel@tonic-gate 	    }
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	return ret;
997*7c478bd9Sstevel@tonic-gate     }
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate     // Construct a Transact object to run a convergence transaction in
1000*7c478bd9Sstevel@tonic-gate     //  a separate thread.
1001*7c478bd9Sstevel@tonic-gate 
Transact(SrvLocMsg msg, Vector ret, int[] msT, int mResults, InetAddress address, boolean continueAfterFound)1002*7c478bd9Sstevel@tonic-gate     Transact(SrvLocMsg msg,
1003*7c478bd9Sstevel@tonic-gate 	     Vector ret,
1004*7c478bd9Sstevel@tonic-gate 	     int[] msT,
1005*7c478bd9Sstevel@tonic-gate 	     int mResults,
1006*7c478bd9Sstevel@tonic-gate 	     InetAddress address,
1007*7c478bd9Sstevel@tonic-gate 	     boolean continueAfterFound) {
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	msgOut = msg;
1010*7c478bd9Sstevel@tonic-gate 	returns = ret;
1011*7c478bd9Sstevel@tonic-gate 	MSTimeouts = msT;
1012*7c478bd9Sstevel@tonic-gate 	maxResults = mResults;
1013*7c478bd9Sstevel@tonic-gate 	this.address = address;
1014*7c478bd9Sstevel@tonic-gate 	this.continueAfterFound = continueAfterFound;
1015*7c478bd9Sstevel@tonic-gate     }
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate     // Run the multicast convergence algorithm.
1018*7c478bd9Sstevel@tonic-gate 
run()1019*7c478bd9Sstevel@tonic-gate     public void run() {
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	Exception xes = null;
1022*7c478bd9Sstevel@tonic-gate 	DatagramSocket ds = null;
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	// Get the config object if we need it.
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	if (config == null) {
1027*7c478bd9Sstevel@tonic-gate 	    config = SLPConfig.getSLPConfig();
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	// Set thread name.
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	if (config.isBroadcastOnly()) {
1034*7c478bd9Sstevel@tonic-gate 	    Thread.currentThread().setName("SLP Broadcast Transact");
1035*7c478bd9Sstevel@tonic-gate 	    address = config.getBroadcastAddress();
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	} else {
1038*7c478bd9Sstevel@tonic-gate 	    Thread.currentThread().setName("SLP Multicast Transact");
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	}
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 	try {
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	    // Multicast out on the default interface only.
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	    ds = config.getMulticastSocketOnInterface(config.getLocalHost(),
1047*7c478bd9Sstevel@tonic-gate 						      true);
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	    // Perform convergence.
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 	    transactConvergeMsg(address,
1052*7c478bd9Sstevel@tonic-gate 				ds,
1053*7c478bd9Sstevel@tonic-gate 				msgOut,
1054*7c478bd9Sstevel@tonic-gate 				returns,
1055*7c478bd9Sstevel@tonic-gate 				MSTimeouts,
1056*7c478bd9Sstevel@tonic-gate 				maxResults,
1057*7c478bd9Sstevel@tonic-gate 				continueAfterFound);
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	    ds.close();
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	    ds = null;
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 	    // Ignore DA_BUSY, the DA may free up later.
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	    if (ex.getErrorCode() != ServiceLocationException.DA_BUSY) {
1068*7c478bd9Sstevel@tonic-gate 		exErr = ex;
1069*7c478bd9Sstevel@tonic-gate 		xes = ex;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	    }
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	} catch (Exception ex) {
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	    // Create new exception to be thrown.
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate 	    xes = ex;
1078*7c478bd9Sstevel@tonic-gate 	    exErr = new ServiceLocationException(
1079*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
1080*7c478bd9Sstevel@tonic-gate 				"passthrough",
1081*7c478bd9Sstevel@tonic-gate 				new Object[] {ex.getMessage()});
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 	} finally {
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	    // Close the socket if it's been opened.
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	    if (ds != null) {
1088*7c478bd9Sstevel@tonic-gate 		ds.close();
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	    }
1091*7c478bd9Sstevel@tonic-gate 	}
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	// Log any errors.
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	if (xes != null) {
1096*7c478bd9Sstevel@tonic-gate 	    StringWriter sw = new StringWriter();
1097*7c478bd9Sstevel@tonic-gate 	    PrintWriter pw = new PrintWriter(sw);
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	    xes.printStackTrace(pw);
1100*7c478bd9Sstevel@tonic-gate 	    pw.flush();
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 	    config.writeLog("multicast_error",
1103*7c478bd9Sstevel@tonic-gate 			    new Object[] {xes.getMessage(),
1104*7c478bd9Sstevel@tonic-gate 					      sw.toString()});
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 	}
1107*7c478bd9Sstevel@tonic-gate     }
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate     /**
1110*7c478bd9Sstevel@tonic-gate      * Send the message using multicast and use convergence to gather the
1111*7c478bd9Sstevel@tonic-gate      * results. Note that this routine must be synchronized because
1112*7c478bd9Sstevel@tonic-gate      * only one multicast can be active at a time; othewise, the client
1113*7c478bd9Sstevel@tonic-gate      * may get back an unexpected result. However, there can be many unicast
1114*7c478bd9Sstevel@tonic-gate      * requests active along with a multicast request, hence the separate
1115*7c478bd9Sstevel@tonic-gate      * thread for multicast.
1116*7c478bd9Sstevel@tonic-gate      *
1117*7c478bd9Sstevel@tonic-gate      * The subtlety of the timing routine is that it will only resend the
1118*7c478bd9Sstevel@tonic-gate      * message when one of the multicast convergence timeout intervals
1119*7c478bd9Sstevel@tonic-gate      * elapses.  Further, for efficiency, it will give up after a complete
1120*7c478bd9Sstevel@tonic-gate      * interval has gone by without receiving any results.  This may mean
1121*7c478bd9Sstevel@tonic-gate      * that the intervals have to be extended in larger networks.  In the
1122*7c478bd9Sstevel@tonic-gate      * common case, multicast convergence will complete under 3 seconds
1123*7c478bd9Sstevel@tonic-gate      * as all results will arrive during the first interval (1 second long)
1124*7c478bd9Sstevel@tonic-gate      * and none will arrive during the second interval.
1125*7c478bd9Sstevel@tonic-gate      *
1126*7c478bd9Sstevel@tonic-gate      * @param     addr  The multicast/broadcast address to send the request to.
1127*7c478bd9Sstevel@tonic-gate      * @param     ds  The datagram socket to send on.
1128*7c478bd9Sstevel@tonic-gate      * @param     msg The message to send.
1129*7c478bd9Sstevel@tonic-gate      * @param     vResult A vector in which to put the returns.
1130*7c478bd9Sstevel@tonic-gate      * @param	msTimeouts Array of timeout values for multicast convergence.
1131*7c478bd9Sstevel@tonic-gate      * @param     maxResults Maximum replies desired.
1132*7c478bd9Sstevel@tonic-gate      * @param	continueAfterFound If true, continue after something is
1133*7c478bd9Sstevel@tonic-gate      *				   found. Try three times if nothing was
1134*7c478bd9Sstevel@tonic-gate      *				   found. If false, exit at the first
1135*7c478bd9Sstevel@tonic-gate      *				   timeout. DA discovery should set this
1136*7c478bd9Sstevel@tonic-gate      *				   to true so as many DAs as possible are
1137*7c478bd9Sstevel@tonic-gate      *				   found, otherwise, it should be false.
1138*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException
1139*7c478bd9Sstevel@tonic-gate      *            If results cannot be obtained in the timeout interval
1140*7c478bd9Sstevel@tonic-gate      *            specified in the 'config.' or
1141*7c478bd9Sstevel@tonic-gate      *            if networking resources cannot be obtained or used
1142*7c478bd9Sstevel@tonic-gate      *            effectively.
1143*7c478bd9Sstevel@tonic-gate      */
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate     static public void
transactConvergeMsg(InetAddress addr, DatagramSocket ds, SrvLocMsg msg, Vector vResult, int[] msTimeouts, int maxResults, boolean continueAfterFound)1146*7c478bd9Sstevel@tonic-gate 	transactConvergeMsg(InetAddress addr,
1147*7c478bd9Sstevel@tonic-gate 			    DatagramSocket ds,
1148*7c478bd9Sstevel@tonic-gate 			    SrvLocMsg   msg,
1149*7c478bd9Sstevel@tonic-gate 			    Vector vResult,
1150*7c478bd9Sstevel@tonic-gate 			    int[] msTimeouts,
1151*7c478bd9Sstevel@tonic-gate 			    int maxResults,
1152*7c478bd9Sstevel@tonic-gate 			    boolean continueAfterFound)
1153*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	// Get the config object if we need it.
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	if (config == null) {
1158*7c478bd9Sstevel@tonic-gate 	    config = SLPConfig.getSLPConfig();
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 	}
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 	int numReplies = 0;
1163*7c478bd9Sstevel@tonic-gate 	int tries = 0;
1164*7c478bd9Sstevel@tonic-gate 	SrvLocMsg rply = null;
1165*7c478bd9Sstevel@tonic-gate 	ByteArrayOutputStream baos = null;
1166*7c478bd9Sstevel@tonic-gate 	int multiMax = config.getMulticastMaximumWait();
1167*7c478bd9Sstevel@tonic-gate 	long lStartTime = System.currentTimeMillis();
1168*7c478bd9Sstevel@tonic-gate 	int mtu = config.getMTU();
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate 	try {
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	    // Send the request for the 1st iteration.  It will be sent again
1173*7c478bd9Sstevel@tonic-gate 	    //  only when the timeout intervals elapse.
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate 	    send(ds, msg, addr);
1176*7c478bd9Sstevel@tonic-gate 	    tries++;
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 	    long lTimeSent = System.currentTimeMillis();
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	    // Continue collecting results only as long as we need more for
1181*7c478bd9Sstevel@tonic-gate 	    //   the 'max results' configuration.
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	    while (numReplies < maxResults) {
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 		// Set up the reply buffer.
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 		byte [] incoming = new byte[mtu];
1188*7c478bd9Sstevel@tonic-gate 		DatagramPacket dprecv =
1189*7c478bd9Sstevel@tonic-gate 		    new DatagramPacket(incoming, incoming.length);
1190*7c478bd9Sstevel@tonic-gate 
1191*7c478bd9Sstevel@tonic-gate 		// Block on receive (no longer than max timeout - time spent).
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 		int iTimeout =
1194*7c478bd9Sstevel@tonic-gate 		    getTimeout(lStartTime, lTimeSent, multiMax, msTimeouts);
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 		if (iTimeout < 0) {
1197*7c478bd9Sstevel@tonic-gate 		    break; // we have no time left!
1198*7c478bd9Sstevel@tonic-gate 		}
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 		ds.setSoTimeout(iTimeout);
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 		try {
1203*7c478bd9Sstevel@tonic-gate 		    ds.receive(dprecv);
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 		} catch (InterruptedIOException ex) {
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 		    // We try sending at least three times, unless there was
1208*7c478bd9Sstevel@tonic-gate 		    // a timeout. If continueAfterFound is false, we exit
1209*7c478bd9Sstevel@tonic-gate 		    // after the first timeout if something was found.
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 		    if ((!continueAfterFound && numReplies > 0) ||
1212*7c478bd9Sstevel@tonic-gate 		(int)(System.currentTimeMillis() - lStartTime) > multiMax ||
1213*7c478bd9Sstevel@tonic-gate 			tries >= 3) {
1214*7c478bd9Sstevel@tonic-gate 			break;
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 		    }
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 		    // Now resend the request...
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 		    send(ds, msg, addr);
1221*7c478bd9Sstevel@tonic-gate 		    tries++;
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate 		    lTimeSent = System.currentTimeMillis();
1224*7c478bd9Sstevel@tonic-gate 		    continue; // since we did not receive anything, continue...
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 		}
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 		// Data was received without timeout or fail.
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 		DataInputStream dis =
1231*7c478bd9Sstevel@tonic-gate 		    new DataInputStream(
1232*7c478bd9Sstevel@tonic-gate 			new ByteArrayInputStream(dprecv.getData()));
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 		InetAddress raddr = dprecv.getAddress();
1235*7c478bd9Sstevel@tonic-gate 		rply = internalize(dis, raddr);
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 		if (!filterRply(msg, rply, raddr)) {
1238*7c478bd9Sstevel@tonic-gate 		    continue;
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 		}
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 		// Add this responder to previous responders. If the message
1243*7c478bd9Sstevel@tonic-gate 		//  was already received but the SA resent because it isn't
1244*7c478bd9Sstevel@tonic-gate 		//  doing multicast convergence correctly, then ignore it.
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 		if (!addPreviousResponder(msg, raddr)) {
1247*7c478bd9Sstevel@tonic-gate 		    continue;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 		}
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 		// Handle any overflow thru TCP.
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 		SrvLocHeader rhdr = rply.getHeader();
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate 		if (rhdr.overflow) {
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 		    rply = transactTCPMsg(raddr, msg, false);
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 		    if (rply == null) {
1260*7c478bd9Sstevel@tonic-gate 			continue;
1261*7c478bd9Sstevel@tonic-gate 
1262*7c478bd9Sstevel@tonic-gate 		    }
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 		    rhdr = rply.getHeader();
1265*7c478bd9Sstevel@tonic-gate 		}
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 		// Add response to list.
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 		if (vResult.size() < maxResults) {
1270*7c478bd9Sstevel@tonic-gate 		    vResult.addElement(rply);
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate 		}
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 		// Increment the number of results returned.
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 		numReplies += rhdr.iNumReplies;
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 		// Exit if we should not continue.
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 		if (!continueAfterFound) {
1281*7c478bd9Sstevel@tonic-gate 		    break;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 		}
1284*7c478bd9Sstevel@tonic-gate 	    }
1285*7c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 	    // If we broke off because the previous responder's list is too
1288*7c478bd9Sstevel@tonic-gate 	    // long, then return, otherwise throw the exception again.
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	    if (ex.getErrorCode() ==
1291*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.PREVIOUS_RESPONDER_OVERFLOW) {
1292*7c478bd9Sstevel@tonic-gate 		return;
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	    }
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate 	    throw ex;
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	    throw
1301*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1302*7c478bd9Sstevel@tonic-gate 				ServiceLocationException.NETWORK_ERROR,
1303*7c478bd9Sstevel@tonic-gate 				"ioexception_conv",
1304*7c478bd9Sstevel@tonic-gate 				new Object[] {ex, ex.getMessage()});
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate 	}
1307*7c478bd9Sstevel@tonic-gate     }
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate     // Calculate the multicast timeout depending on where we are in the loop.
1310*7c478bd9Sstevel@tonic-gate 
1311*7c478bd9Sstevel@tonic-gate     static private int
getTimeout(long lStart, long lSent, int iTimeout, int[] a_iTOs)1312*7c478bd9Sstevel@tonic-gate 	getTimeout(long lStart, long lSent, int iTimeout, int[] a_iTOs) {
1313*7c478bd9Sstevel@tonic-gate 	int iTotal = (int)(lSent - lStart);
1314*7c478bd9Sstevel@tonic-gate 
1315*7c478bd9Sstevel@tonic-gate 	if (iTimeout < iTotal) {
1316*7c478bd9Sstevel@tonic-gate 	    return -1;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	}
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate 	int iWaitTotal = 0;
1321*7c478bd9Sstevel@tonic-gate 	int i;
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < a_iTOs.length; i++) {
1324*7c478bd9Sstevel@tonic-gate 	    iWaitTotal += a_iTOs[i];
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 	    int iTillNext = (iWaitTotal - iTotal);
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 	    if (iTotal < iWaitTotal) {
1329*7c478bd9Sstevel@tonic-gate 		if (iTimeout < (iTotal + iTillNext)) {
1330*7c478bd9Sstevel@tonic-gate 		    return (iTimeout - iTotal);  // max to wait is iTimeout
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 		} else {
1333*7c478bd9Sstevel@tonic-gate 		    return iTillNext; // otherwise wait till next interval
1334*7c478bd9Sstevel@tonic-gate 		}
1335*7c478bd9Sstevel@tonic-gate 	    }
1336*7c478bd9Sstevel@tonic-gate 	}
1337*7c478bd9Sstevel@tonic-gate 
1338*7c478bd9Sstevel@tonic-gate 	return -1; // if we get here we have waited past all of the timeouts
1339*7c478bd9Sstevel@tonic-gate     }
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate     static {
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate 	config = SLPConfig.getSLPConfig();
1344*7c478bd9Sstevel@tonic-gate 
1345*7c478bd9Sstevel@tonic-gate     }
1346*7c478bd9Sstevel@tonic-gate }
1347