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