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