/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*/
// RequestHandler.java: Handle an incoming request in a separate thread.
// Author: James Kempf
// Created On: Mon May 18 14:00:27 1998
// Last Modified By: James Kempf
// Last Modified On: Mon Mar 8 16:12:13 1999
// Update Count: 173
//
/**
* Handle an incoming request in a separate thread. The request
* may have arrived via datagram, or it may have arrived via
* stream.
*
* @author James Kempf, Erik Guttman
*/
// Keeps track of in progress requests
// When a request handler gets GC'd, make sure it's open socket is closed.
// We simply let the exception propagate, because it is ignored.
}
port = 427;
try {
} catch (ServiceLocationException ex) {
// Taken care of in initialization code.
}
}
// Request arrived via stream. Set the incoming socket, spawn
// a separate thread in which to run.
"rh_null_sock",
new Object[0]);
"ls_null_config",
new Object[0]);
try {
} catch (ServiceLocationException ex) {
// Taken care of in initialization code.
}
}
// Request arrived via datagram. Set the incoming packet, spawn
// a separate thread in which to run.
"rh_null_packy",
new Object[0]);
"ls_null_config",
new Object[0]);
try {
} catch (ServiceLocationException ex) {
// Taken care of in initialziation code.
}
}
/**
* Return a stringified buffer, suitable for printing, for
* debugging.
*
* @param bytes The byte buffer.
* @return A string with the ASCII characters as characters, otherwise
* convert to escape notation.
*/
for (i = 0; i < n; i++) {
byte b = bytes[i];
if ((b >= 0x21) && (b < 0x7e)) {
} else {
}
}
}
// If a stream thread, then get the request first. Process the
// request and reply to client.
public void run() {
// Is this a stream or datagram thread?
// Label appropriately.
// Set the socket to block until there are bytes to read.
try {
} catch (SocketException ex) {
}
}
// get DA Table
try {
} catch (ServiceLocationException e) {
// Taken care of in initialziation code.
}
// Stream needs to loop through until requests are completed.
handleStream();
try {
} catch (IOException ex) {
}
}
} else {
// Label appropriately.
// Copy xid for use in hash key.
byte[] xidBuf = new byte[2];
// If this request is already in progress, drop new request.
int xid = 0;
boolean there = false;
synchronized (inProgress) {
if (!there) {
}
}
// Drop if we are processing it already.
if (there) {
new Object[] {clientAddr,
interfac});
}
return;
}
// We can simply cut to the chase and process the datagram
// request.
try {
// Open a data output stream for the outgoing request. There
// is no buffer for reply or it is empty, the request was
// multicast and nothing was sent back.
}
} catch (IOException ex) {
// No excuse for an EOF exception here.
new Object[] {clientAddr,
ex.getMessage()});
}
}
// Remove the lock for this request. We do this just before the
// run() method exits and the thread expires to reduce the
// window in which a new copy of the request could come in.
// We need to be sure that we only remove if it is this
// request handler.
synchronized (inProgress) {
if (rh == this) {
}
}
}
}
// Handle an incoming stream.
private void handleStream() {
try {
} else {
// use the socket
}
// Loop while the client still wants to send something. But we
// only read one SLP message at a time on the connection,
// returning if it there are no more bytes to read. Note that
// until something shows up.
do {
// Handle the new request.
// Forward reg or dereg to foreign DAs that need to know
// about it.
try {
} catch (ServiceLocationException ex) {
new Object[] {
ex.getMessage()});
}
}
// If there was a parse error, then break out and close the
// stream, because it may have lingering bytes.
new Object[] {clientAddr,
interfac});
break;
}
} while (true);
} catch (EOFException ex) {
new Object[] {clientAddr,
interfac});
}
} catch (IOException ex) {
// An error occured during input.
new Object[] {clientAddr,
ex.getMessage()});
}
}
}
// Send a byte buffer reply through a datagram socket.
try {
// Open the socket.
ds = new DatagramSocket();
// Format the outgoing packet.
// Send the reply.
// Forward reg or dereg to foreign DAs that need to know about it.
try {
} catch (ServiceLocationException ex) {
new Object[] {
ex.getMessage()});
}
}
} catch (SocketException ex) {
// Failure in reply.
new Object[] {clientAddr,
ex.getMessage()});
}
} catch (IOException ex) {
// Failure in reply.
"rh_ioexception_reply",
new Object[] {clientAddr,
ex.getMessage()});
}
} finally {
}
}
}
// Handle an incoming stream containing an SLP request.
private boolean
boolean isTCP)
throws IOException {
boolean parseError = false;
// Decode the message.
// If there was an error converting the request, then don't
// process further.
}
// Dispatch the message to the service table.
// If no reply, then simply return.
new Object[] {
interfac});
}
return parseError;
}
} else {
// Drop if multicast.
new Object[] {
interfac});
}
} else if (isTCP) {
// Set the parse error flag so that the stream gets closed.
// It's easier than trying to keep track of the number of
// bytes read. Otherwise, the remnents of the message
// hang around.
parseError = true;
}
}
}
// Reply to the client if necessary. Note that if the reply is null
// here, there was a problem parsing the message in and so formulating
// a reply may be impossible (for example, the message may not
// be parsable beyond the function code.
// Parse out the message.
try {
} catch (ServiceLocationException sle) {
}
}
"rh_header_class_error",
try {
} catch (ServiceLocationException exx) {
}
}
// Print error message.
}
interfac});
}
return parseError;
}
/**
* Internalize the byte array in the input stream into a SrvLocMsg
*
* @param dis The input stream containing the packet.
* @param viaTCP True if the outgoing stream is via TCP.
* If null is returned, it means that the function code was
* not recognized.
* If any error occurs during creation, an error request is
* returned with the error code set.
*/
private SrvLocMsg
"rh_null_bais",
new Object[0]);
try {
// Pull off the version number and function code.
byte[] b = new byte[2];
} catch (IOException ex) {
// Print an error message, but only if not EOF.
if (!(ex instanceof EOFException)) {
}
// Throw the exception, so streams can terminate.
throw ex;
}
try {
// Unrecognized version number if header not returned.
// We only throw an exception if the version number
// is greater than the current default version number.
// otherwise, the packet is from an earlier version
// of the protocol and should be ignored if we are
// not operating in compatibility mode.
// code problem...
throw
"rh_version_number_error",
interfac});
} else {
return null;
}
}
// If we've come via TCP, clear the packet length so the
// eventual reply won't be checked for overflow.
if (viaTCP) {
}
// Parse the header.
// Parse body.
// Parse options, if any.
}
// If this is a DAAdvert or an SAAdvert, or there's no header,
// return null cause we don't need to return anything or
// can't.
// Let header create message.
}
}
return msg;
}
// Print an error message for errors during internalization.
if (ex instanceof ServiceLocationException) {
} else if (ex instanceof IllegalArgumentException) {
}
new Object[] {clientAddr,
}
}
/**
* Dispatch the service request object to the service table.
* The SA table is used for the following:
*
* @param rqst Service request object.
* @return A SrvLocMsg object to reply with, or null if no reply.
*/
// Check CDAAdvert and CSAAdvert before we check the previous
// responders list, because they don't have any.
// For V1, V2 messages know.
msg.setIsUnsolicited(true);
// If passive detection is off, ignore it, but only if it wasn't
// a signal to stop.
if (!config.passiveDADetection() &&
msg.isUnsolicited() &&
!msg.isGoingDown()) {
}
// We've been asked to terminate.
// Check scopes.
config.getSAConfiguredScopes(), true);
// If all scopes not equal, it isn't a shutdown message for us.
} else {
try {
} catch (ServiceLocationException ex) {
// Ignore, we're going down anyway and it's
// just a report.
}
// It is a shutdown message for us.
config.traceDATraffic()) {
new Object[] {interfaces,
daAttributes});
}
// We don't reply, which means that the client will
// time out.
}
} else {
// The implementation specific DA table handles this.
}
return null;
// We are only interested in it if we may be going down.
// Check scopes.
config.getSAConfiguredScopes(), true);
// If all scopes not equal, it isn't a shutdown message for us.
try {
} catch (ServiceLocationException ex) {
// Ignore, we're going down anyway and it's just a
// report.
}
// It is a shutdown message for us.
config.traceDATraffic()) {
new Object[] {interfaces,
saAttributes});
}
}
}
// Otherwise, drop it for now.
interfac});
}
return null;
}
}
// If we are on the previous responder list, then ignore this
// request.
if (isPreviousResponder(hdr)) {
interfac});
}
return null;
}
// Now check requests with previous responders.
} else { // error...
"rh_rqst_type_err",
}
return null;
}
// Dispatch a service registration.
// Report error if the message was multicast.
new Object[] {"SrvReg",
interfac});
}
return null;
}
// Register the request.
// Forward to foreign DAs if no error.
}
}
return rply;
}
// Dispatch a service deregistration.
// Report error if the message was multicast.
new Object[] {"SrvDereg",
interfac});
}
return null;
}
// If the message came from the local host, use the SA store.
// Forward to foreign DAs if no error.
}
}
return rply;
}
// Dispatch a service type message.
// Drop if this is a DA and the request was multicast. DAs
// do not respond to multicast, except for DAAdverts.
new Object[] {"SrvTypeRqst",
interfac});
}
return null;
}
// Filter multicast replies to remove null and error returns.
if (mcast &&
new Object[] {"SrvTypeRqst",
interfac});
}
return null;
}
return rply;
}
// Dispatch an attribute request.
// Drop if this is a DA and the request was multicast. DAs
// do not respond to multicast, except for DAAdverts.
new Object[] {"AttrRqst",
interfac});
}
return null;
}
// Filter multicast replies to remove null and error returns.
if (mcast &&
new Object[] {"AttrRqst",
interfac});
}
return null;
}
return rply;
}
// Dispatch a service request.
// We need to special case if this is a request for a DAAdvert
// and we are a DA or an SAAdvert and we are an SA only.
// Reply only if a DA.
// Return a DAAdvert for this DA.
config);
"DAAdvert",
""});
}
}
// If there was an error and the request was multicast, drop it
// by returning null.
mcast) {
new Object[] {
"DA SrvRqst",
interfac});
}
return null;
}
return rply;
// Note that we reply if we are a DA because somebody may want
// SA attributes.
// We report error for unicast SA service request.
if (!mcast) {
new Object[] {
"SA SrvRqst",
interfac});
}
return null;
}
// Return a SAAdvert for this SA.
try {
config);
} catch (ServiceLocationException ex) {
"SAAdvert",
ex.getMessage()});
}
new Object[] {"SA SrvRqst",
interfac});
}
return rply;
}
// Drop if this is a DA and the request was multicast. DAs
// do not respond to multicast, except for DAAdverts.
new Object[] {"SrvRqst",
interfac});
}
return null;
}
// Filter multicast replies to remove null and error returns.
if (mcast &&
new Object[] {"SrvRqst",
interfac});
}
return null;
}
return smrply;
}
// Return true if the host address matches one of the local interfaces.
try {
} catch (UnknownHostException ex) {
// We simply ignore it.
return false;
}
return true;
}
return false;
}
/**
* Return whether this was previous responder. Only do so if the
* request was multicast.
*
* @return True if this host was a previous responder.
*/
// If there are no previous responders, then return false,
// because they aren't used for this message. Also for
// messages that are not multicast.
return false;
}
Enumeration e = null;
// Check for matches against this address.
try {
return true;
}
} catch (UnknownHostException ex) {
}
}
return false;
}
// Initialize the SLPv2 header parser class when we are loaded.
static {
}
}