ServiceTable.java revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* ident "%Z%%M% %I% %E% SMI"
*
* Copyright (c) 1999 by Sun Microsystems, Inc.
* All rights reserved.
*
*/
// SCCS Status: @(#)ServiceTable.java 2.7 11/20/97
// ServiceTable.java: Storage of all services.
// Author: James Kempf
// Created On: Fri Oct 10 14:23:25 1997
// Last Modified By: James Kempf
// Last Modified On: Thu Apr 1 10:33:46 1999
// Update Count: 461
//
/**
* The ServiceTable object records all service registrations. Note
* that any exceptions internal to the service table are processed
* and either returned as SrvRply objects or are reported.
*
* @version 2.7 97/11/20
* @author James Kempf
*/
class ServiceTable extends Object {
// Key for SDAAdvert class.
//
// Instance variables.
//
// The service store.
//
// Class variables.
// System properties.
// Singleton objects for the service tables.
// The ager thread.
// Time to sleep. Adjusted depending on incoming URLs.
//
// Creation of singleton.
//
// Protected constructor.
protected ServiceTable() {
return;
}
// Create the ager thread.
thrAger = new AgerThread();
// Set the priority low, so other things (like active discovery)
// take priority.
}
/**
* Return an SA service store.
*
* @return The distinguished table object.
*/
static ServiceTable getServiceTable()
throws ServiceLocationException {
}
table = createServiceTable();
}
return table;
}
/**
* Return a service table object.
*
* @return The service table object.
*/
private static ServiceTable createServiceTable()
throws ServiceLocationException {
return table;
}
//
// Support for serializated registrations.
//
/**
* If any serialized registrations are pending, then unserialize
* and register.
*/
public void deserializeTable() {
// If there are any serialized registrations, then get
// them and perform registrations.
if (serializedURL != null) {
}
}
}
/**
* Serialize the table to the URL.
*
* @param URL String giving the URL to which the store should be
* serialized.
*/
// Open an object output stream for the URL, serialize through
// the factory.
try {
// Serialize the store.
} catch (MalformedURLException ex) {
} catch (UnsupportedEncodingException ex) {
} catch (IOException ex) {
} catch (ServiceLocationException ex) {
}
}
// Read proxy registrations from the URL.
// Open an object input stream for the URL, deserialize through
// the factory.
try {
// Deserialize the objects.
serStore =
} catch (MalformedURLException ex) {
new Object[] {serializedURL});
} catch (UnsupportedEncodingException ex) {
new Object[] {serializedURL});
} catch (IOException ex) {
new Object[] {
ex.getMessage()});
} catch (ServiceLocationException ex) {
new Object[] {
ex.getMessage()});
}
return serStore;
}
// Walk the table, performing actual registrations on all records.
// Walk the table.
while (en.hasMoreElements()) {
// Note that we can't use the Advertiser to register here,
// because we may not be listening yet for registrations.
// We need to do this all by hand.
try {
// Create a registration message for refreshing.
surl,
null,
null);
// We externalize to a server side message if authentication
// is needed. This creates the auth blocks for the scopes.
// Doing this in any other way is alot more complicated,
// although doing it this way seems kludgy.
if (hasURLSig || hasAttrSig) {
// Now we've got it, after much effort. Get the auths.
}
// Now we've got to put the registration into the
// PermSARegTable. Again, we do everything by hand
// because we can't use Advertiser.
if (surl.getIsPermanent()) {
}
// Report registration.
new Object[] {
surl,
scopes});
}
} catch (ServiceLocationException ex) {
new Object[] {
surl,
new Object[] {
surl,
}
}
}
//
// Record aging.
//
//
// Run the thread that ages out records.
//
private class AgerThread extends Thread {
public void run() {
setName("SLP Service Table Age-out");
while (true) {
try {
// Record when we went to sleep.
// Sleep for the minimum amount of time needed before we
// must wake up and check.
} catch (InterruptedException ie) {
// A new registration came in. Calculate how much time
// remains until we would have woken up. If this is
// less than the new sleepyTime, then we set the alarm
// for this time. If it is more, then we set the alarm
// for the new sleepyTime.
long remainingSleepTime =
remainingSleepTime = // just in case...
if (remainingSleepTime < alarmTime) {
}
continue; // we don't have to walk yet...
}
// Walk the table, get the new alarm and sleepy times.
}
}
}
}
/**
* Age the service store.
*/
// this method cannot be private... due to compiler weakness
void ageStore() {
try {
// We synchronize in case somebody registers and tries to
// change sleepy time.
synchronized (store) {
// Track unregistered services.
for (i = 0; i < n; i++) {
trackRegisteredServiceTypes(); // it's deleted...
}
}
} catch (RuntimeException ex) {
} catch (ServiceLocationException ex) {
}
}
//
// SLP Service Table operations (register, deregister, etc.)
//
/**
* Process the registration and record if no errors found.
*
* @param req Service registration request message.
* @return SrvLocMsg A service registration acknowledgement.
*/
short errorCode =
try {
// If a sig block came in, verify it.
}
}
// Check whether the URL has a zero lifetime. If so, it
// isn't cached.
throw
"st_zero",
new Object[0]);
}
// Check if the service type is restricted. If so, nobody outside
// this process is allowed to register it.
// Check that attribute signature bit on implies URL signature
// bit on.
throw
"st_attr_sig",
new Object[0]);
}
// If a signature and the fresh bit was not set, error since signed
// registrations don't allow updating.
throw
"st_prot_update",
new Object[0]);
}
// Check if scopes are supported.
if (!areSupportedScopes(scopes)) {
throw
"st_scope_unsup",
new Object[0]);
}
// Check if the reg is signed and auth is off or vice versa.
// Check is really simple. If security is on, then all regs
// that aren't, and vice versa.
throw
"st_unprot_non_reg",
new Object[0]);
} else if (!conf.getHasSecurity() &&
throw
"st_prot_non_reg",
new Object[0]);
}
// Merge any duplicates.
for (i = 0; i < n; i++) {
attr,
false);
}
// Store register or update.
boolean existing = false;
if (fresh) {
attrSig);
// Track registred service types in case we get a
// SAAdvert solicatation.
} else {
}
// Create the reply.
new Object[] {
surl,
scopes});
}
}
// Calculate time increment until next update. This is used
// to adjust the sleep interval in the ager thread.
// We synchronize in case the ager thread is in the middle
// of trying to set the time.
synchronized (store) {
// If we need to wake up sooner, adjust the sleep time.
if (sTime < sleepyTime) {
sleepyTime = sTime;
// Interrupt the thread so we go back to
// sleep for the right amount of time.
}
}
return ack;
} catch (ServiceLocationException ex) {
new Object[] {
surl,
scopes});
}
} catch (RuntimeException ex) {
// These exceptions are not declared in throws but can occur
// anywhere.
}
}
/**
* Process the deregistration and return the result in a reply.
*
* @param req Service deregistration request message.
* @return SrvLocMsg A service registration acknowledgement.
*/
// We need to determine whether this is an attribute deregistration
// or a deregistration of the entire URL.
try {
// Verify if signature is nonnull.
}
// Check if the service type is restricted. If so, nobody outside
// this process is allowed to register it.
// Error if there's a signature and attempt at deleting attributes.
throw
"st_prot_attr_dereg",
new Object[0]);
}
// Check if scope is protected and auth is off or vice versa.
// Check is really simple. If security is on, then all scopes
// that aren't, and vice versa.
throw
"st_unprot_non_dereg",
new Object[0]);
throw
"st_prot_non_dereg",
new Object[0]);
}
// If it's a service URL, then deregister the URL.
// Track registred service types in case we get a
// SAAdvert solicatation.
} else {
// Just delete the attributes.
}
// Create the reply.
new Object[] {
surl,
tags});
}
new Object[] {locationMsg});
}
return ack;
} catch (ServiceLocationException ex) {
"st_dereg_drop" : "st_dereg_attr_drop"),
new Object[] {
surl,
tags});
}
} catch (RuntimeException ex) {
// These exceptions are not declared in throws but can occur
// anywhere.
}
}
/**
* Process the service type request and return the result in a reply.
*
* @param req Service type request message.
* @return SrvTypeRply A service type reply.
*/
try {
// Check whether the scope is supported.
if (!areSupportedScopes(scopes)) {
throw
"st_scope_unsup",
new Object[0]);
}
// Get the vector of service types in the store, independent
// of language.
// Create the reply.
new Object[] {
types});
}
return ack;
} catch (ServiceLocationException ex) {
new Object[] {
}
} catch (RuntimeException ex) {
// These exceptions are not declared in throws but can occur
// anywhere.
}
}
/**
* Process the service request and return the result in a reply.
*
* @param req Service request message.
* @return SrvRply A service reply.
*/
try {
// Check whether the scope is supported.
if (!areSupportedScopes(scopes)) {
throw
"st_scope_unsup",
new Object[0]);
}
// Get the hashtable of returns.
locale);
// Get the hashtable of services v.s. scopes, and signatures, if
// any.
// for each candidate URL, make sure it has the requested SPI
// (if any)
while (allSurls.hasMoreElements()) {
// doesn't have the requested SPI
}
}
}
// Create return message.
new Object[] {
signatures});
}
return ack;
} catch (ServiceLocationException ex) {
new Object[] {
locale});
}
} catch (RuntimeException ex) {
// These exceptions are not declared in throws but can occur
// anywhere.
}
}
/**
* Process the attribute request and return the result in a reply.
*
* @param req Attribute request message.
* @return AttrRply An attribute reply.
*/
// We need to determine whether this is a request for attributes
// on a specific URL or for an entire service type.
try {
// Check whether the scope is supported.
if (!areSupportedScopes(scopes)) {
throw
"st_scope_unsup",
new Object[0]);
}
// If it's a service URL, then get the attributes just for
// that URL.
if (serviceType == null) {
// If the attrs are signed, then error if any tags, since
// we must ask for *all* attributes in for a signed reg
throw
"st_par_attr",
new Object[0]);
}
// Get the attributes and signatures.
// make sure the attr has the requested SPI (if any)
// return empty
attributes = new Vector();
}
}
} else {
throw
"st_par_attr",
new Object[0]);
}
// Otherwise find the attributes for all service types.
}
new ServiceType(serviceType));
// Create the reply.
"st_st_attr" : "st_url_attr"),
new Object[] {
tags,
attributes});
}
return ack;
} catch (ServiceLocationException ex) {
"st_url_attr_drop"),
new Object[] {
tags,
locale});
}
} catch (RuntimeException ex) {
// These exceptions are not declared in throws but can occur
// anywhere.
}
}
// Return the service record corresponding to the URL.
}
//
// Utility methods.
//
//
//
// Check whether the type is restricted, through an exception if so.
throws ServiceLocationException {
throw
"st_restricted_type",
}
}
// Insert a record for type "service-agent" with attributes having
// the types currently supported, if the new URL is not on the
// list of supported types. This allows us to perform queries
// for supported service types.
private void trackRegisteredServiceTypes()
throws ServiceLocationException {
// First find the types.
// Get preconfigured attributes.
// Make an attribute with the service types.
types);
// Construct URL to use on all interfaces.
int i, n = interfaces.size();
for (i = 0; i < n; i++) {
// Make a new registration for this SA.
null,
null); // we could sign, but we do that later...
}
// Note that we don't need a refresh on the URLs because they
// will get refreshed when the service URLs that they track
// are refreshed. If the tracked URLs aren't refreshed, then
// these will get updated when the tracked URLs age out.
}
// Return true if the scopes in the vector are supported by the DA
// or SA server.
int i = 0;
// Remove it if we don't support it.
// This will shift the Vector's elements down one, so
// don't increment i
} else {
i++;
}
}
return false;
}
return true;
}
/**
* Return the sleep increment from the URL lifetime. Used by the
* ServiceStore to calculate the new sleep interval in addition
* to this class, when a new URL comes in. The algorithm
* subtracts x% of the lifetime from the lifetime and schedules the
* timeout at that time.
*
* @param url The URL to use for calculation.
* @return The sleep interval.
*/
long increment =
// If URL lives only one second, update every half second.
if (sTime <= 0) {
sTime = 500;
}
return sTime;
}
// Make a DAADvert for the DA service request. This only applies
// to DAs, not to SA servers.
try {
// If security is on, proceed only if we can sign as rqst.spi
throw new ServiceLocationException(
"st_cant_sign_as",
}
// Get the hashtable of service URLs v.s. scopes.
// Go through the table checking whether the IP address came back.
boolean foundIt = false;
while (urls.hasMoreElements()) {
foundIt = true;
break;
}
}
// If we didn't find anything, make a null service reply.
if (!foundIt) {
}
} catch (ServiceLocationException ex) {
}
}
// Make a DAAdvert from the input arguments.
short xid,
throws ServiceLocationException {
// If this is a request for a V1 Advert, truncate the scopes vector
// since DA solicitations in V1 are always unscoped
}
// Check if we support scopes first. If not, return an
// error reply unless the scope vector is zero. Upper layers
// must sort out whether this is a unicast or multicast.
throw
"st_scope_unsup",
new Object[0]);
}
// Get the service store's timestamp. This must be the
// time since last stateless reboot for a stateful store,
// or the current time.
url,
conf.getDAAttributes());
return advert;
}
// Make a SAADvert for the SA service request. This only applies
// to SA servers, not DA's. Note that we only advertise the "public"
// scopes, not the private ones.
throws ServiceLocationException {
// If security is on, proceed only if we can sign as rqst.spi
throw new ServiceLocationException(
"st_cant_sign_as",
}
// Check if we support scopes first. Note that this may allow
// someone to get at the SA only scopes off machine, but that's
// OK. Since the SAAdvert is only ever multicast, this is OK.
return null;
}
// If the scopes vector is null, then use all configured scopes.
}
// Check to be sure the query matches.
// If it doesn't, we don't need to return anything.
// Indicates we don't support the service type.
if (!en.hasMoreElements()) {
return null;
}
// Find the URL to use. The interface on which the message came in
// needs to match one of the registered URLs.
while (en.hasMoreElements()) {
addr,
break;
}
}
// If none of the URLs matched this interface, then return null.
return null;
}
// Find the SA's attributes.
new Vector(),
// Construct return.
return
xid,
url,
attrs);
}
/**
* Report a fatal exception to the log.
*
* @param ex The exception to report.
*/
}
}
/**
* Report a nonfatal exception to the log.
*
* @param ex The exception to report.
* @param args The method arguments.
* @param store The service store being processed.
*/
}
}
/**
* Report an exception to the log.
*
* @param isFatal Indicates whether the exception is fatal or not.
* @param ex The exception to report.
* @param args A potentially null vector of arguments to the
* method where the exception was caught.
*/
private static void
// Get the backtrace.
} else if (ex instanceof ServiceLocationException) {
}
for (i = 0; i < n; i++) {
}
new Object[] {
msg,
}
}