You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by rj...@apache.org on 2009/06/09 14:00:32 UTC
svn commit: r782968 [4/7] - in /directory/sandbox/slp: ./
src/main/java/org/apache/directory/slp/
src/main/java/org/apache/directory/slp/codec/
src/main/java/org/apache/directory/slp/extensions/
src/main/java/org/apache/directory/slp/impl/ src/main/jav...
Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/PlatformAbstraction.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/PlatformAbstraction.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/PlatformAbstraction.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/PlatformAbstraction.java Tue Jun 9 12:00:29 2009
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.slp.impl;
+
+import org.apache.directory.slp.impl.filter.Filter;
+
+/**
+ * Platform abstraction interface. Used to hide the different implementations
+ * for the OSGi platform and for stand-alone Java.
+ *
+ * @author Jan S. Rellermeyer
+ */
+public interface PlatformAbstraction {
+
+ /**
+ * Write a debug message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logDebug(String message);
+
+ /**
+ * Write a debug message to the log.
+ *
+ * @param message
+ * the message.
+ * @param exception
+ * an exception.
+ */
+ void logDebug(String message, Throwable exception);
+
+ /**
+ * Trace a generic message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logTraceMessage(String string);
+
+ /**
+ * Trace a registration to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logTraceReg(String string);
+
+ /**
+ * Trace a drop to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logTraceDrop(String string);
+
+ /**
+ * Write a warning message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logWarning(String message);
+
+ /**
+ * Write a warning message to the log.
+ *
+ * @param message
+ * the message.
+ * @param exception
+ * an exception.
+ */
+ void logWarning(String message, Throwable exception);
+
+ /**
+ * Write an error message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logError(String message);
+
+ /**
+ * Write an error message to the log.
+ *
+ * @param message
+ * the message.
+ * @param exception
+ * an exception.
+ */
+ void logError(String message, Throwable exception);
+
+ /**
+ * Create an LDAP filter.
+ *
+ * @param filterString
+ * the filter string.
+ * @return an LDAP filter object.
+ */
+ Filter createFilter(String filterString);
+}
Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/PlatformAbstraction.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPAttributeImpl.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPAttributeImpl.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPAttributeImpl.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPAttributeImpl.java Tue Jun 9 12:00:29 2009
@@ -0,0 +1,374 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.slp.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.slp.OpaqueValue;
+import org.apache.directory.slp.SLPAttribute;
+import org.apache.directory.slp.ServiceLocationException;
+
+
+/**
+ *
+ * @author Lorenz Breu
+ */
+public class SLPAttributeImpl implements SLPAttribute {
+
+ private List values;
+ private String name = "";
+ private int type;
+ private String typeString = "";
+
+
+ /**
+ * Creates a new SLPAttributeImpl with the given name and values: "(name=values)"
+ *
+ * @param name
+ * The attibute name
+ * @param a_values
+ * The value(s) of the attribute. Types are checked on creation
+ * @throws ServiceLocationException
+ * If the types of values are not consistent
+ */
+ public SLPAttributeImpl(String name,List<String> a_values) throws ServiceLocationException{
+ this.name=name;
+ type = checkAndSetType(a_values);
+
+ }
+
+ /**
+ * Creates a new SLPAttributeImpl with the given name and values: "(name=values)"
+ *
+ * @param name
+ * The attibute name
+ * @param a_values
+ * The value(s) of the attribute. Types are checked on creation
+ * @throws ServiceLocationException
+ * If the types of values are not consistent
+ */
+ public SLPAttributeImpl(String name,String[] a_values) throws ServiceLocationException{
+ this.name=name;
+ type = checkAndSetType(a_values);
+
+ }
+
+
+ /**
+ * Creates a new SLPAttributeImpl as a KEYWORD
+ *
+ * @param name
+ * The attribute/keyword name
+ */
+ public SLPAttributeImpl(String name){
+ this.name=name;
+ type=KEYWORD_AT;
+ }
+
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#count()
+ */
+ public int count() {
+ return values.size();
+ }
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#getBooleanValues()
+ */
+ public Boolean[] getBooleanValues() {
+ if (type==BOOLEAN_AT){
+ return (Boolean[]) values.toArray(new Boolean[values.size()]);
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#getIntegerValues()
+ */
+ public Integer[] getIntegerValues() {
+ if (type==INTEGER_AT){
+ return (Integer[]) values.toArray(new Integer[values.size()]);
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#getName()
+ */
+ public String getName() {
+ return name;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#getOpaqueValues()
+ */
+ public OpaqueValue[] getOpaqueValues() {
+ if (type==OPAQUE_AT){
+ return (OpaqueValue[]) values.toArray(new OpaqueValue[values.size()]);
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#getStringValues()
+ */
+ public String[] getStringValues() {
+ String[] res = new String[values.size()];
+ for (int i=0; i<res.length;i++){
+ res[i] = values.get(i).toString();
+ }
+ return res;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#getType()
+ */
+ public int getType() {
+ return type;
+ }
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#getTypeString()
+ */
+ public String getTypeString() {
+ return typeString;
+ }
+
+
+ /* (non-Javadoc)
+ * @see ch.ethz.iks.slp.SLPAttribute#isKeyword()
+ */
+ public boolean isKeyword() {
+ if (type==KEYWORD_AT){
+ return true;
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString(){
+ if (isKeyword()){
+ return name;
+ }
+ String res = "("+name+"=";
+ for (Object o:values){
+ res+=o.toString()+", ";
+ }
+ res=res.substring(0,res.length()-2)+")";
+ return res;
+ }
+
+ /**
+ * merges the values of another SLPAttribute with the same name and type into the ones of this one.
+ * Silently discards attributes with different names and/or types
+ *
+ * @param other
+ * The other SLPAttribute to be merged into this one
+ *
+ */
+ public void merge(SLPAttribute other){
+ if (!other.getName().equals(name) || other.getType()!=type){
+ return;
+ }
+ switch(type){
+ case STRING_AT:
+ String[] ovs = other.getStringValues();
+ for (int i=0;i<ovs.length;i++){
+ if (!values.contains(ovs[i])){
+ values.add(ovs[i]);
+ }
+ }
+ break;
+ case INTEGER_AT:
+ Integer[] ovi = other.getIntegerValues();
+ for (int i=0;i<ovi.length;i++){
+ if (!values.contains(ovi[i])){
+ values.add(ovi[i]);
+ }
+ }
+ break;
+ case BOOLEAN_AT:
+ Boolean[] ovb = other.getBooleanValues();
+ for (int i=0;i<ovb.length;i++){
+ if (!values.contains(ovb[i])){
+ values.add(ovb[i]);
+ }
+ }
+ break;
+ case OPAQUE_AT:
+ OpaqueValue[] ovo = other.getOpaqueValues();
+ for (int i=0;i<ovo.length;i++){
+ if (!values.contains(ovo[i])){
+ values.add(ovo[i]);
+ }
+ }
+ break;
+ }
+
+ }
+
+
+ /**
+ * Ensures the types on a List of Strings are consistent according to SLP RFC2608.
+ * The values are set if no errors are encountered.
+ *
+ * @param a_values
+ * The values to be checked
+ * @return
+ * The type of the values
+ * @throws ServiceLocationException
+ * INTERNAL_SYSTEM_ERROR if inconsistent types are discovered
+ */
+ private int checkAndSetType(List<String> a_values) throws ServiceLocationException{
+ int t = -1;
+ List v;
+ if (a_values.size()<1){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"no values given for this attribute "+name);
+ }
+ String init = a_values.get(0).trim();
+ if (init.startsWith("\\FF")){
+ t=OPAQUE_AT;
+ v=new ArrayList<OpaqueValue>();
+ v.add(new OpaqueValue(init));
+ } else if (init.toLowerCase().equals("true") || init.toLowerCase().equals("false")){
+ t=BOOLEAN_AT;
+ v=new ArrayList<Boolean>();
+ v.add(Boolean.valueOf(init));
+ } else {
+ try {
+ int vi = Integer.parseInt(init);
+ t=INTEGER_AT;
+ v=new ArrayList<Integer>();
+ v.add(vi);
+ } catch (NumberFormatException nfe){
+ t=STRING_AT;
+ v=new ArrayList<String>();
+ v.add(init);
+ }
+ }
+
+ for (int i=1;i<a_values.size();i++){
+ init=a_values.get(i).trim();
+ if (init.startsWith("\\FF")){
+ if (t!=OPAQUE_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(new OpaqueValue(init));
+
+ } else if (init.toLowerCase().equals("true") || init.toLowerCase().equals("false")){
+ if (t!=BOOLEAN_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(Boolean.valueOf(init));
+ } else {
+ try {
+ int vi = Integer.parseInt(init);
+ if (t!=INTEGER_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(vi);
+ } catch (NumberFormatException nfe){
+ if (t!=STRING_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(init);
+ }
+ }
+
+ }
+ values=v;
+ return t;
+
+ }
+
+ /**
+ * Ensures the types on a List of Strings are consistent according to SLP RFC2608.
+ * The values are set if no errors are encountered.
+ *
+ * @param a_values
+ * The values to be checked
+ * @return
+ * The type of the values
+ * @throws ServiceLocationException
+ * INTERNAL_SYSTEM_ERROR if inconsistent types are discovered
+ */
+ private int checkAndSetType(String[] a_values) throws ServiceLocationException{
+ int t = -1;
+ List v;
+ String init = a_values[0].trim();
+ if (init.startsWith("\\FF")){
+ t=OPAQUE_AT;
+ v=new ArrayList<OpaqueValue>();
+ v.add(new OpaqueValue(init));
+ } else if (init.toLowerCase().equals("true") || init.toLowerCase().equals("false")){
+ t=BOOLEAN_AT;
+ v=new ArrayList<Boolean>();
+ v.add(Boolean.valueOf(init));
+ } else {
+ try {
+ int vi = Integer.parseInt(init);
+ t=INTEGER_AT;
+ v=new ArrayList<Integer>();
+ v.add(vi);
+ } catch (NumberFormatException nfe){
+ t=STRING_AT;
+ v=new ArrayList<String>();
+ v.add(init);
+ }
+ }
+
+ for (int i=1;i<a_values.length;i++){
+ init=a_values[i];
+ if (init.startsWith("\\FF")){
+ if (t!=OPAQUE_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(new OpaqueValue(init));
+
+ } else if (init.toLowerCase().equals("true") || init.toLowerCase().equals("false")){
+ if (t!=BOOLEAN_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(Boolean.valueOf(init));
+ } else {
+ try {
+ int vi = Integer.parseInt(init);
+ if (t!=INTEGER_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(vi);
+ } catch (NumberFormatException nfe){
+ if (t!=STRING_AT){
+ throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"inconsistent types for this attribute "+name);
+ }
+ v.add(init);
+ }
+ }
+
+ }
+
+ return t;
+
+ }
+}
Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPAttributeImpl.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPConfiguration.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPConfiguration.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPConfiguration.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPConfiguration.java Tue Jun 9 12:00:29 2009
@@ -0,0 +1,607 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.slp.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+
+/**
+ * SLPConfiguration object holds all configurable properties.
+ *
+ * @author Jan S. Rellermeyer
+ */
+public class SLPConfiguration {
+
+ private static final String USE_SCOPES_PROP = "net.slp.useScopes";
+
+ private static final String USE_SCOPES_DEFAULT = "DEFAULT";
+
+ private static final String DA_ADDRESSES_PROP = "net.slp.DAAddresses";
+
+ private static final String DA_ADDRESSES_DEFAULT = null;
+
+ private static final String WAIT_TIME_PROP = "net.slp.waitTime";
+
+ private static final String WAIT_TIME_DEFAULT = "1000";
+
+ private static final String TRACE_DATRAFFIC_PROP = "net.slp.traceDATraffic";
+
+ private static final String TRACE_DATRAFFIC_DEFAULT = "false";
+
+ private static final String TRACE_MESSAGE_PROP = "net.slp.traceMsg";
+
+ private static final String TRACE_MESSAGE_DEFAULT = "false";
+
+ private static final String TRACE_DROP_PROP = "net.slp.traceDrop";
+
+ private static final String TRACE_DROP_DEFAULT = "false";
+
+ private static final String TRACE_REG_PROP = "net.slp.traceReg";
+
+ private static final String TRACE_REG_DEFAULT = "false";
+
+ private static final String MCAST_TTL_PROP = "net.slp.multicastTTL";
+
+ private static final String MCAST_TTL_DEFAULT = "255";
+
+ private static final String MCAST_MAX_WAIT_PROP = "net.slp.multicastMaximumWait";
+
+ private static final String MCAST_MAX_WAIT_DEFAULT = "15000";
+
+ private static final String MCAST_TIMEOUTS_PROP = "net.slp.multicastTimeouts";
+
+ private static final String MCAST_TIMEOUTS_DEFAULT = "3000,2000,1500,1000,750,500";
+
+ private static final String DATAGRAM_MAX_WAIT_PROP = "net.slp.datagramMaximumWait";
+
+ private static final String DATAGRAM_MAX_WAIT_DEFAULT = "5000";
+
+ private static final String DATAGRAM_TIMEOUTS_PROP = "net.slp.datagramTimeouts";
+
+ private static final String DATAGRAM_TIMEOUTS_DEFAULT = "3000,3000,3000,3000,3000";
+
+ private static final String MTU_PROP = "net.slp.MTU";
+
+ private static final String MTU_DEFAULT = "1400";
+
+ private static final String SECURITY_ENABLED_PROP = "net.slp.securityEnabled";
+
+ private static final String SECURITY_ENABLED_DEFAULT = "false";
+
+ private static final String SPI_PROP = "net.slp.spi";
+
+ private static final String SPI_DEFAULT = "";
+
+ private static final String PRIVATE_KEY_PROP = "net.slp.privateKey.";
+
+ private static final String PUBLIC_KEY_PROP = "net.slp.publicKey.";
+
+ private static final String INTERFACES_PROP = "net.slp.interfaces";
+
+ private static final String INTERFACES_DEFAULT = null;
+
+ private static final String NO_DA_DISCOVERY_PROP = "net.slp.noDADiscovery";
+
+ private static final String PORT_PROP = "net.slp.port";
+
+ private static final String DEFAULT_PORT = "427";
+
+ private static final String DEFAULT_CONVERGENCE_FAILERCOUNT = "2";
+
+ private static final String CONVERGENCE_FAILERCOUNT_PROP = "net.slp.failercount";
+
+ private static final String DEBUG_ENABLED_PROP = "ch.ethz.iks.slp.debug";
+
+ private static final String CONFIG_START_WAIT_PROP = "net.slp.configStartWait";
+
+ private static final String CONFIG_START_WAIT_DEFAULT = "3000";
+
+ private static final String CONFIG_DA_FIND_PROP = "net.slp.configDaFind";
+
+ private static final String CONFIG_DA_FIND_DEFAULT = "900000";
+
+ private static final String CONFIG_REG_ACTIVE_PROP = "net.slp.configRegActive";
+
+ private static final String CONFIG_REG_ACTIVE_DEFAULT = "1000";
+
+ private static final String CONFIG_RETRY_PROP = "net.slp.configRetry";
+
+ private static final String CONFIG_RETRY_DEFAULT = "2000";
+
+ private static final String CONFIG_RETRY_MAX_PROP = "net.slp.configRetryMax";
+
+ private static final String CONFIG_RETRY_MAX_DEFAULT = "15000";
+
+ private static final String CONFIG_DA_BEAT_PROP = "net.slp.DAHeartBeat";
+
+ private static final String CONFIG_DA_BEAT_DEFAULT = "10800000"; // 3h
+
+ private static final String CONFIG_DA_ATTRIBUTES_PROP = "net.slp.DAAttributes";
+
+ private static final String CONFIG_DA_ATTRIBUTES_DEFAULT = "";
+
+ private static String[] INTERFACES;
+
+ private static int PORT;
+
+ private static String SCOPES;
+
+ private static boolean NO_DA_DISCOVERY;
+
+ private static String[] DA_ADDRESSES;
+
+ private static boolean TRACE_DA_TRAFFIC;
+
+ private static boolean TRACE_MESSAGES;
+
+ private static boolean TRACE_DROP;
+
+ private static boolean TRACE_REG;
+
+ private static int MCAST_TTL;
+
+ private static int MCAST_MAX_WAIT;
+
+ private static int[] MCAST_TIMEOUTS;
+
+ private static int DATAGRAM_MAX_WAIT;
+
+ private static int[] DATAGRAM_TIMEOUTS;
+
+ private static int MTU;
+
+ private static boolean SECURITY_ENABLED;
+
+ private static String SPI;
+
+ private static int WAIT_TIME;
+
+ private static Map<String, PublicKey> PUBLIC_KEY_CACHE;
+
+ private static Map<String, PrivateKey> PRIVATE_KEY_CACHE;
+
+ private static int CONVERGENCE_FAILERCOUNT;
+
+ private static boolean DEBUG_ENABLED;
+
+ private static int CONFIG_START_WAIT;
+
+ private static int CONFIG_DA_FIND;
+
+ private static int CONFIG_REG_ACTIVE;
+
+ private static int CONFIG_RETRY;
+
+ private static int CONFIG_RETRY_MAX;
+
+ private static int CONFIG_DA_BEAT;
+
+ private static String CONFIG_DA_ATTRIBUTES;
+
+ /**
+ * create a new SLPConfiguration from properties.
+ *
+ * @param properties
+ * properties.
+ */
+ SLPConfiguration() {
+ processProperties(System.getProperties());
+ }
+
+ /**
+ * create a new SLPConfiguration from config file.
+ *
+ * @param file
+ * the file.
+ * @throws IOException
+ * in case of IO errors.
+ */
+ SLPConfiguration(final File file) throws IOException {
+ Properties props = new Properties();
+ props.load(new FileInputStream(file));
+ props.putAll(System.getProperties());
+ processProperties(props);
+ }
+
+ private static void processProperties(final Properties props) {
+ String ifaces = props.getProperty(INTERFACES_PROP, INTERFACES_DEFAULT);
+ if (ifaces == null) {
+ INTERFACES = null;
+ } else {
+ INTERFACES = (String[]) SLPUtils.stringToStringArray(ifaces, ",");
+ }
+ PORT = Integer.parseInt(props.getProperty(PORT_PROP, DEFAULT_PORT));
+ SCOPES = props.getProperty(USE_SCOPES_PROP, USE_SCOPES_DEFAULT);
+ NO_DA_DISCOVERY = new Boolean(props.getProperty(NO_DA_DISCOVERY_PROP,
+ "false")).booleanValue();
+ final String dAs = props.getProperty(DA_ADDRESSES_PROP,
+ DA_ADDRESSES_DEFAULT);
+ if (dAs == null) {
+ DA_ADDRESSES = null;
+ } else {
+ DA_ADDRESSES = SLPUtils.stringToStringArray(dAs, ",");
+ }
+ TRACE_DA_TRAFFIC = new Boolean(props.getProperty(TRACE_DATRAFFIC_PROP,
+ TRACE_DATRAFFIC_DEFAULT)).booleanValue();
+ TRACE_MESSAGES = new Boolean(props.getProperty(TRACE_MESSAGE_PROP,
+ TRACE_MESSAGE_DEFAULT)).booleanValue();
+
+ TRACE_DROP = new Boolean(props.getProperty(TRACE_DROP_PROP,
+ TRACE_DROP_DEFAULT)).booleanValue();
+
+ TRACE_REG = new Boolean(props.getProperty(TRACE_REG_PROP,
+ TRACE_REG_DEFAULT)).booleanValue();
+
+ MCAST_TTL = Integer.parseInt(props.getProperty(MCAST_TTL_PROP,
+ MCAST_TTL_DEFAULT));
+
+ MCAST_MAX_WAIT = Integer.parseInt(props.getProperty(
+ MCAST_MAX_WAIT_PROP, MCAST_MAX_WAIT_DEFAULT));
+
+ DATAGRAM_MAX_WAIT = Integer.parseInt(props.getProperty(
+ DATAGRAM_MAX_WAIT_PROP, DATAGRAM_MAX_WAIT_DEFAULT));
+
+ MCAST_TIMEOUTS = parseTimeouts(props.getProperty(MCAST_TIMEOUTS_PROP,
+ MCAST_TIMEOUTS_DEFAULT));
+
+ DATAGRAM_TIMEOUTS = parseTimeouts(props.getProperty(
+ DATAGRAM_TIMEOUTS_PROP, DATAGRAM_TIMEOUTS_DEFAULT));
+
+ MTU = Integer.parseInt(props.getProperty(MTU_PROP, MTU_DEFAULT));
+
+ SECURITY_ENABLED = new Boolean(props.getProperty(SECURITY_ENABLED_PROP,
+ SECURITY_ENABLED_DEFAULT)).booleanValue();
+
+ SPI = props.getProperty(SPI_PROP, SPI_DEFAULT);
+
+ WAIT_TIME = Integer.parseInt(props.getProperty(WAIT_TIME_PROP,
+ WAIT_TIME_DEFAULT));
+
+ CONVERGENCE_FAILERCOUNT = Integer.parseInt(props.getProperty(
+ CONVERGENCE_FAILERCOUNT_PROP, DEFAULT_CONVERGENCE_FAILERCOUNT));
+
+ DEBUG_ENABLED = new Boolean(props.getProperty(DEBUG_ENABLED_PROP,
+ "false")).booleanValue();
+
+ CONFIG_START_WAIT = Integer.parseInt(props.getProperty(
+ CONFIG_START_WAIT_PROP, CONFIG_START_WAIT_DEFAULT));
+
+ CONFIG_DA_FIND = Integer.parseInt(props.getProperty(
+ CONFIG_DA_FIND_PROP, CONFIG_DA_FIND_DEFAULT));
+
+ CONFIG_REG_ACTIVE = Integer.parseInt(props.getProperty(
+ CONFIG_REG_ACTIVE_PROP, CONFIG_REG_ACTIVE_DEFAULT));
+
+ CONFIG_RETRY = Integer.parseInt(props.getProperty(CONFIG_RETRY_PROP,
+ CONFIG_RETRY_DEFAULT));
+
+ CONFIG_RETRY_MAX = Integer.parseInt(props.getProperty(
+ CONFIG_RETRY_MAX_PROP, CONFIG_RETRY_MAX_DEFAULT));
+
+ CONFIG_DA_BEAT = Integer.parseInt(props.getProperty(
+ CONFIG_DA_BEAT_PROP, CONFIG_DA_BEAT_DEFAULT));
+
+ CONFIG_DA_ATTRIBUTES = props.getProperty(CONFIG_DA_ATTRIBUTES_PROP,
+ CONFIG_DA_ATTRIBUTES_DEFAULT);
+
+ if (SECURITY_ENABLED) {
+ PUBLIC_KEY_CACHE = new HashMap<String, PublicKey>(0);
+ PRIVATE_KEY_CACHE = new HashMap<String, PrivateKey>(0);
+ }
+ }
+
+ /**
+ * returns the network interfaces.
+ *
+ * @return interfaces
+ */
+ String[] getInterfaces() {
+ return INTERFACES;
+ }
+
+ /**
+ * get the port.
+ *
+ * @return the port
+ */
+ int getPort() {
+ return PORT;
+ }
+
+ /**
+ * get the scopes.
+ *
+ * @return the scopes.
+ */
+ public String getScopes() {
+ return SCOPES;
+ }
+
+ /**
+ * get the predefined DA addresses.
+ *
+ * @return the DA addresses.
+ */
+ String[] getDaAddresses() {
+ return DA_ADDRESSES;
+ }
+
+ /**
+ * get no DA discovery
+ *
+ * @return true, if DA discovery is disabled
+ */
+ boolean getNoDaDiscovery() {
+ return NO_DA_DISCOVERY;
+ }
+
+ /**
+ * trace DA traffic ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceDaTraffic() {
+ return TRACE_DA_TRAFFIC;
+ }
+
+ /**
+ * trace messages ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceMessage() {
+ return TRACE_MESSAGES;
+ }
+
+ /**
+ * trace dropped messages ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceDrop() {
+ return TRACE_DROP;
+ }
+
+ /**
+ * trace registrations ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceReg() {
+ return TRACE_REG;
+ }
+
+ /**
+ * get the multicast TTL.
+ *
+ * @return the multicast TTL.
+ */
+ int getMcastTTL() {
+ return MCAST_TTL;
+ }
+
+ /**
+ * get the multicast max wait time.
+ *
+ * @return the max wait time.
+ */
+ int getMcastMaxWait() {
+ return MCAST_MAX_WAIT;
+ }
+
+ /**
+ * get the datagram max wait time.
+ *
+ * @return the datagram max wait time.
+ */
+ int getDatagramMaxWait() {
+ return DATAGRAM_MAX_WAIT;
+ }
+
+ /**
+ * parse timeout lists.
+ *
+ * @param s
+ * a timeout list string.
+ * @return the timeout int array.
+ */
+ private static int[] parseTimeouts(final String s) {
+ StringTokenizer st = new StringTokenizer(s, ",");
+ int[] timeouts = new int[st.countTokens()];
+ for (int i = 0; i < timeouts.length; i++) {
+ timeouts[i] = Integer.parseInt(st.nextToken());
+ }
+ return timeouts;
+ }
+
+ /**
+ * get the multicast timeouts.
+ *
+ * @return the multicast timeouts.
+ */
+ int[] getMcastTimeouts() {
+ return MCAST_TIMEOUTS;
+ }
+
+ /**
+ * get the datagram timeouts.
+ *
+ * @return the datagram timeouts.
+ */
+ int[] getDatagramTimeouts() {
+ return DATAGRAM_TIMEOUTS;
+ }
+
+ /**
+ * get the MTU.
+ *
+ * @return the MTU.
+ */
+ public int getMTU() {
+ return MTU;
+ }
+
+ /**
+ * is security enabled ?
+ *
+ * @return true if security is enabled.
+ */
+ public boolean getSecurityEnabled() {
+ return SECURITY_ENABLED;
+ }
+
+ /**
+ * get the SPIs.
+ *
+ * @return the SPI string list.
+ */
+ public String getSPI() {
+ return SPI;
+ }
+
+ /**
+ * get the public key for a certain SPI.
+ *
+ * @param spi
+ * the SPI.
+ * @return the location of the public key.
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ public PublicKey getPublicKey(final String spi) throws IOException,
+ GeneralSecurityException {
+ PublicKey key = (PublicKey) PUBLIC_KEY_CACHE.get(spi);
+ if (key != null) {
+ return key;
+ }
+ FileInputStream keyfis = new FileInputStream(System
+ .getProperty(PUBLIC_KEY_PROP + spi));
+ byte[] encKey = new byte[keyfis.available()];
+ keyfis.read(encKey);
+ keyfis.close();
+ X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+ key = keyFactory.generatePublic(pubKeySpec);
+ PUBLIC_KEY_CACHE.put(spi, key);
+ return key;
+ }
+
+ /**
+ * get the private key for a certain SPI.
+ *
+ * @param spi
+ * the SPI.
+ * @return the location of the private key.
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ public PrivateKey getPrivateKey(final String spi) throws IOException,
+ GeneralSecurityException {
+ PrivateKey key = (PrivateKey) PRIVATE_KEY_CACHE.get(spi);
+ if (key != null) {
+ return key;
+ }
+ FileInputStream keyfis = new FileInputStream(System
+ .getProperty(PRIVATE_KEY_PROP + spi));
+
+ byte[] encKey = new byte[keyfis.available()];
+ keyfis.read(encKey);
+ keyfis.close();
+
+ PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
+
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+ key = keyFactory.generatePrivate(privKeySpec);
+ PRIVATE_KEY_CACHE.put(spi, key);
+ return key;
+ }
+
+ /**
+ * get the default wait time.
+ *
+ * @return the default wait time.
+ */
+ int getWaitTime() {
+ return WAIT_TIME;
+ }
+
+ /**
+ * Defines after how many inconclusive multicastConvergence cycles the
+ * attempt is aborted. It indirectly defines how many multicast convergence
+ * {@link SLPMessage}.SRVTYPERQST get send during an attempt.
+ *
+ * This value can be seen as an heuristical optimization to stop multicast
+ * convergence early if inconclusive
+ *
+ * @return how many inconclusive cycles are allowed
+ */
+ int getConvergenceFailerCount() {
+ return CONVERGENCE_FAILERCOUNT;
+ }
+
+ public boolean getDebugEnabled() {
+ return DEBUG_ENABLED;
+ }
+
+ public int getTCPTimeout() {
+ // TODO wire this to the properties if necessary
+ return 5000; // 5sec
+ }
+
+ public int getConfigStartWait() {
+ return CONFIG_START_WAIT;
+ }
+
+ public int getConfigDaFind() {
+ return CONFIG_DA_FIND;
+ }
+
+ public int getConfigRegActive() {
+ return CONFIG_REG_ACTIVE;
+ }
+
+ public int getConfigRetry() {
+ return CONFIG_RETRY;
+ }
+
+ public int getConfigRetryMax() {
+ return CONFIG_RETRY_MAX;
+ }
+
+ public int getConfigDABeat() {
+ return CONFIG_DA_BEAT;
+ }
+
+ public String getConfigDAAttributes() {
+ return CONFIG_DA_ATTRIBUTES;
+ }
+}
Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPConfiguration.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPCore.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPCore.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPCore.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPCore.java Tue Jun 9 12:00:29 2009
@@ -0,0 +1,1422 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.slp.impl;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.Executors;
+
+import org.apache.directory.slp.ReplyFuture;
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.ServiceStore;
+import org.apache.directory.slp.ServiceType;
+import org.apache.directory.slp.codec.SLPProtocolCodecFactory;
+import org.apache.directory.slp.impl.da.DirectoryAgentDaemon;
+import org.apache.directory.slp.messages.AbstractSLPMessage;
+import org.apache.directory.slp.messages.AbstractSLPReplyMessage;
+import org.apache.directory.slp.messages.AbstractSLPRequestMessage;
+import org.apache.directory.slp.messages.DAAdvertisementMessage;
+import org.apache.directory.slp.messages.ServiceRequestMessage;
+import org.apache.mina.core.future.ConnectFuture;
+import org.apache.mina.core.future.WriteFuture;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.mina.filter.executor.ExecutorFilter;
+import org.apache.mina.transport.socket.DatagramSessionConfig;
+import org.apache.mina.transport.socket.apr.AprDatagramAcceptor;
+import org.apache.mina.transport.socket.apr.AprDatagramConnector;
+import org.apache.mina.transport.socket.apr.AprDatagramSession;
+import org.apache.mina.transport.socket.apr.AprSocketAcceptor;
+import org.apache.mina.transport.socket.apr.AprSocketConnector;
+
+/**
+ * the core class of the jSLP implementation.
+ * <code>ch.ethz.iks.slp.ServiceLocationManager</code> inherits from this
+ * class.
+ *
+ * @see ch.ethz.iks.slp.impl.ServiceLocationManager
+ * @author Jan S. Rellermeyer
+ */
+public class SLPCore {
+
+ private static volatile boolean isInitialized = false;
+ private static volatile boolean isListening = false; // is the UA listening for adverts?
+ private static volatile boolean isSAInitialized = false;
+ private static volatile boolean isDAInitialized = false;
+
+ protected static PlatformAbstraction platform;
+
+ /**
+ * the default empty locale. Used for messages that don't specify a locale.
+ */
+ static public final Locale DEFAULT_LOCALE = Locale.getDefault();
+
+ /**
+ * the port for SLP communication.
+ */
+ public static final int SLP_PORT;
+
+ /**
+ * the reserved (standard) port.
+ */
+ public static final int SLP_RESERVED_PORT = 427;
+
+ /**
+ * the standard SLP multicast address.
+ */
+ public static final String SLP_MCAST_ADDRESS = "239.255.255.253";
+
+ /**
+ *
+ */
+ public static final InetAddress MCAST_ADDRESS;
+
+ /**
+ * the SLP configuration.
+ */
+ public static final SLPConfiguration CONFIG;
+
+ /**
+ * currently only for debugging.
+ */
+ static final boolean TCP_ONLY = false;
+
+ /**
+ * the standard service type for DAs.
+ */
+ static final String SLP_DA_TYPE = "service:directory-agent";
+
+ /**
+ * my own ip. Used to check if this peer is already in the previous
+ * responder list.
+ */
+ static String[] myIPs;
+
+ /**
+ * configured to perform no DA discovery ?
+ */
+ static final boolean noDiscovery;
+ static String discoveryException="";
+
+ /**
+ * the constructor for <code>Advertiser</code> instances, if an
+ * implementation exists.
+ */
+ protected static final Constructor advertiser;
+
+ /**
+ * the constructor for <code>Locator</code> instances, if an
+ * implementation exists.
+ */
+ protected static final Constructor locator;
+
+ /**
+ * the constructor for <code>SLPDaemon</code> instances, if an
+ * implementation exists.
+ */
+ private static final Constructor daemonConstr;
+
+ /**
+ * the daemon instance, if the implementation exists and no other daemon is
+ * already running on the machine.
+ */
+ private static SLPDaemon daemon;
+
+
+ /**
+ * the constructor for <code>DirectoryAgent</code> instances, if an
+ * implementation exists.
+ */
+ protected static final Constructor directoryAgent;
+
+ /**
+ * the constructor for <code>DirectoryAgentDaemon</code> instances, if an
+ * implementation exists.
+ */
+ protected static final Constructor daDaemonConstr;
+
+
+ /**
+ * the DA daemon instance, if the implementation exists and no other DA is
+ * already running on the machine.
+ */
+ public static DirectoryAgentDaemon daDaemon;
+
+
+ /**
+ * the next free XID.
+ */
+ private static short nextXid;
+
+ /**
+ * used to asynchronously receive replies. query XID -> reply queue (List)
+ */
+ private static Map<Integer,List<AbstractSLPMessage>> replyListeners = new HashMap<Integer,List<AbstractSLPMessage>>();
+
+ /**
+ * Map of DAs:
+ *
+ * String scope -> list of Strings of DA URLs.
+ */
+ static Map<String,List<String>> dAs = new HashMap<String,List<String>>();
+
+
+ /**
+ * Map of sBTs for known DAs:
+ *
+ * String IP-Address -> Integer (32bit timestamp)
+ *
+ */
+ static Map<String,Integer> statelessBootTimestamps = new HashMap<String, Integer>();
+
+
+ /**
+ * Map of DA SPIs:
+ *
+ * String DA URL -> String String.
+ */
+ static Map<String,List<String>> dASPIs = new HashMap<String,List<String>>(); // DA URL -> List of SPIs
+
+
+ /**
+ * timestamp of last DA lookup. According to RFC2608 a DA lookup may only be performed every CONFIG_DA_FIND seconds
+ */
+ private static long lastDaLookup = 0;
+
+ static InetAddress LOCALHOST;
+
+ /**
+ * MINA Connectors (outgoing)
+ *
+ * SLPCore sends all messages, yet receives only replies.
+ * The daemon listens for incoming UDP and TCP packets (requests) on SLP_PORT
+ *
+ */
+ private static AprDatagramConnector sender; //sends UDP packets (default)
+ private static AprDatagramConnector[] senderList; //one for each interface
+
+
+ //We also need a SocketConnector to send messages by TCP if necessary (and get the reply)
+ private static AprSocketConnector tcpsender;
+
+ //we also need dynamic acceptors to be able to listen for replies to multicast messages
+ private static AprDatagramAcceptor[] receiverList;
+
+ // the main receiver listening on the SLP port.
+ // UAs: receive multicast DAAdverts
+ // SAs: receive SrvRqsts
+ // DAs: the whole !#
+ private static AprDatagramAcceptor multicastAcceptor;
+ private static AprSocketAcceptor multicastTCPAcceptor;
+
+ private static final SLPHandler handler = new SLPHandler();
+
+
+ /**
+ * initialize the core class.
+ */
+ static {
+ try {
+ LOCALHOST = InetAddress.getLocalHost();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ final Class[] locale = new Class[] { Locale.class };
+
+ // check, if an Advertiser implementation is available
+ Constructor constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.AdvertiserImpl")
+ .getConstructor(locale);
+ } catch (Exception e) {
+ }
+ advertiser = constr;
+
+ // check, if a Locator implementation is available
+ constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.LocatorImpl")
+ .getConstructor(locale);
+ } catch (Exception e) {
+ }
+ locator = constr;
+
+ // check, if a DA is available
+ constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.da.DirectoryAgentImpl")
+ .getConstructor(new Class[]{});
+ } catch (Exception e) {
+ }
+ directoryAgent = constr;
+
+ // check, if a Daemon is available
+ constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.SLPDaemonImpl")
+ .getConstructor(new Class[]{});
+ } catch (Exception e) {
+ }
+ daemonConstr = constr;
+
+
+ // check, if a DADaemon is available
+ constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.da.DirectoryAgentDaemonImpl")
+ .getConstructor(new Class[]{});
+ } catch (Exception e) {
+ }
+ daDaemonConstr = constr;
+
+
+ // read in the property file, if it exists
+ File propFile = new File("jslp.properties");
+ SLPConfiguration config;
+ try {
+ config = propFile.exists() ? new SLPConfiguration(propFile)
+ : new SLPConfiguration();
+ } catch (IOException e1) {
+ System.out.println("Could not parse the property file" + propFile.toString());
+ e1.printStackTrace();
+ config = new SLPConfiguration();
+ }
+ CONFIG = config;
+
+ noDiscovery = CONFIG.getNoDaDiscovery();
+
+ // determine the interfaces on which jSLP runs on
+ String[] IPs = CONFIG.getInterfaces();
+ if (IPs == null) {
+ List<String> workingInterfaces = new ArrayList<String>();
+ try {
+ // changed by Lorenz to work on Debian systems
+ Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
+ for (NetworkInterface intf : Collections.list(nets)){
+ Enumeration<InetAddress> inetAdds = intf.getInetAddresses();
+ String ip = "";
+ while (inetAdds.hasMoreElements()){
+ ip = inetAdds.nextElement().getHostAddress();
+ if (ip.indexOf(":")==-1){
+ break;
+ }
+ }
+
+ if (!ip.equals("") && ip.indexOf(":")==-1){
+ workingInterfaces.add(ip);
+ }
+
+ }
+ } catch (SocketException se){
+
+ }
+ IPs = workingInterfaces.toArray(new String[]{});
+
+
+ }
+ myIPs = IPs;
+ SLP_PORT = CONFIG.getPort();
+
+ // initialize the XID with a random number
+ nextXid = (short) Math.round(Math.random() * Short.MAX_VALUE);
+
+ InetAddress mcast = null;
+ try {
+ mcast = InetAddress.getByName(SLPCore.SLP_MCAST_ADDRESS);
+ } catch (UnknownHostException e1) {
+ e1.printStackTrace();
+ }
+
+ MCAST_ADDRESS = mcast;
+ }
+
+
+
+ /**
+ * Initialize the daemon for the SA
+ */
+ protected static void initSA(){
+
+ if (isSAInitialized){
+ return;
+ }
+ if (!isInitialized){
+ init();
+ }
+ if (!isListening) {
+ try {
+ initializeListeners();
+ } catch (ServiceLocationException sle){
+ System.out.println("[SLPCORE]: Unable to initialize MINA aceptors, aborting");
+ //System.exit(1);
+ }
+ }
+
+ // check, if there is already a SLP daemon runnung on port 427
+ // that can be either a jSLP daemon, or an OpenSLP daemon or something
+ // else. If not, try to start a new daemon instance.
+ if (daemonConstr != null) {
+ try {
+ daemon = (SLPDaemon) daemonConstr.newInstance(new Object[]{});
+ isSAInitialized=true;
+ } catch (Exception e) {
+ daemon = null;
+ }
+ }
+ isSAInitialized = true;
+
+ String[] daAddresses = CONFIG.getDaAddresses();
+ if (daAddresses == null) {
+ if (noDiscovery) {
+ throw new IllegalArgumentException(
+ "Configuration 'net.slp.noDaDiscovery=true' requires a non-empty list of preconfigured DAs");
+ }
+ } else {
+ try {
+
+ // process the preconfigured DAs
+ final ServiceRequestMessage req = new ServiceRequestMessage();
+ req.setServiceType(new ServiceType(SLP_DA_TYPE));
+ for (int i = 0; i < daAddresses.length; i++) {
+ try {
+ InetAddress addr = InetAddress.getByName(daAddresses[i]);
+ discoveryException = daAddresses[i];
+ InetSocketAddress sock = new InetSocketAddress(addr,SLP_PORT);
+ DAAdvertisementMessage daa = (DAAdvertisementMessage) sendUnicastMessage(
+ req,sock, true);
+ if (daa==null){
+ platform.logWarning("Error communicating with " + daAddresses[i]);
+ continue;
+ }
+ discoveryException = "";
+ String[] scopes = (String[]) daa.getScopes();
+ for (int j = 0; j < scopes.length; j++) {
+ platform.logDebug("jSLP is adding DA, "
+ + daAddresses[i] + " for the Scope, "
+ + scopes[j]);
+ SLPUtils.addValue(dAs, scopes[i].toLowerCase(), daAddresses[i]);
+ }
+ } catch (ServiceLocationException e) {
+ discoveryException = "";
+ platform.logWarning("Error communicating with " + daAddresses[i], e);
+ } catch (UnknownHostException e) {
+ discoveryException="";
+ platform.logWarning("Unknown net.slp.DAAddresses address: " + daAddresses[i], e);
+ }
+ }
+ } catch (IllegalArgumentException ise) {
+ discoveryException="";
+ platform.logDebug("May never happen", ise);
+ }
+ }
+
+ }
+
+ protected static void initDA(ServiceStore store){
+
+ if (isDAInitialized){
+ return;
+ }
+ if (!isInitialized){
+ init();
+ }
+ if (!isListening) {
+ try {
+ initializeListeners();
+ } catch (ServiceLocationException sle){
+ System.out.println("[SLPCORE]: Unable to initialize MINA aceptors, aborting");
+ }
+ }
+
+
+
+ // TODO: localization
+ if (daDaemonConstr != null) {
+ try {
+ daDaemon = (DirectoryAgentDaemon) daDaemonConstr.newInstance(new Object[]{});
+ daDaemon.setStore(store);
+ isDAInitialized=true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ daDaemon = null;
+ }
+ }
+
+ }
+
+
+ protected static void init() {
+ if(isInitialized) {
+ return;
+ }
+
+ initializeMina();
+
+
+ isInitialized = true;
+
+ platform.logDebug("jSLP is running on the following interfaces: "
+ + java.util.Arrays.asList(myIPs));
+ platform.logDebug("jSLP is using port: " + SLP_PORT);
+
+ String[] daAddresses = CONFIG.getDaAddresses();
+ if (daAddresses == null) {
+ if (noDiscovery) {
+ throw new IllegalArgumentException(
+ "Configuration 'net.slp.noDaDiscovery=true' requires a non-empty list of preconfigured DAs");
+ }
+ } else {
+ try {
+
+ // process the preconfigured DAs
+ final ServiceRequestMessage req = new ServiceRequestMessage();
+ req.setServiceType(new ServiceType(SLP_DA_TYPE));
+ for (int i = 0; i < daAddresses.length; i++) {
+ try {
+ InetAddress addr = InetAddress.getByName(daAddresses[i]);
+ InetSocketAddress sock = new InetSocketAddress(addr,SLP_PORT);
+ DAAdvertisementMessage daa = (DAAdvertisementMessage) sendUnicastMessage(
+ req,sock, true);
+ if (daa==null){
+ platform.logWarning("Error communicating with " + daAddresses[i]);
+ continue;
+ }
+ String[] scopes = (String[]) daa.getScopes();
+ for (int j = 0; j < scopes.length; j++) {
+ platform.logDebug("jSLP is adding DA, "
+ + daAddresses[i] + " for the Scope, "
+ + scopes[j]);
+ SLPUtils.addValue(dAs, scopes[i].toLowerCase(), daAddresses[i]);
+ }
+ } catch (ServiceLocationException e) {
+ platform.logWarning("Error communicating with " + daAddresses[i], e);
+ } catch (UnknownHostException e) {
+ platform.logWarning("Unknown net.slp.DAAddresses address: " + daAddresses[i], e);
+ }
+ }
+ } catch (IllegalArgumentException ise) {
+ platform.logDebug("May never happen", ise);
+ }
+ }
+
+ if (!noDiscovery) {
+ // perform an initial lookup
+ try {
+ List<String> scopes = new ArrayList<String>();
+ scopes.add("default");
+ // wait CONFIG_START_WAIT
+ // added by Lorenz just to make it clear that RFC2608 section 12.2.1 has been considered
+ long rand = Math.round(Math.random()*CONFIG.getConfigStartWait());
+ Thread.sleep(rand);
+ daLookup((String[]) scopes.toArray(new String[]{}));
+ } catch (Exception e) {
+ platform.logError("Exception in initial DA lookup", e);
+ }
+ }
+
+ }
+
+ public static synchronized void shutdownAdvertiser(){
+ daemon=null;
+ isSAInitialized= false;
+ }
+
+ public static synchronized void shutdownDirectoryAgent(){
+ if (daDaemon!=null){
+ daDaemon.shutdown();
+ }
+ daDaemon=null;
+ isDAInitialized = false;
+ }
+
+// public static synchronized void shutdownUserAgent(){
+// if (!isSAInitialized && !isDAInitialized && isInitialized){
+// sender.dispose();
+// for (AprDatagramConnector ac : senderList){
+// ac.dispose();
+// }
+// tcpsender.dispose();
+// for (AprDatagramAcceptor aa : receiverList){
+// aa.dispose();
+// }
+// multicastAcceptor.dispose();
+// multicastTCPAcceptor.dispose();
+// isInitialized = false;
+// }
+// }
+
+
+ /**
+ * get my own IP.
+ *
+ * @return the own IP.
+ */
+ public static InetAddress getMyIP() {
+ try {
+ int i = 0;
+ String result = myIPs[i];
+ while ((result.equals("127.0.0.1") || result.equals("127.0.1.1")) && (myIPs.length > (i+1))){
+ result = myIPs[i];
+ }
+
+ if (result.equals("127.0.1.1")){
+ return InetAddress.getByName("127.0.0.1");
+ }
+ return InetAddress.getByName(result);
+
+ } catch (UnknownHostException e) {
+ platform.logError("Unknown net.slp.interfaces address: " + myIPs[0], e);
+ return null;
+ }
+ }
+
+ /**
+ * get the list of all available scopes.
+ *
+ * @return a List of all available scopes. RFC 2614 proposes
+ * <code>Vector</code> but jSLP returns <code>List</code>.
+ * @throws ServiceLocationException
+ * in case of an exception in the underlying framework.
+ */
+ public static List<String> findScopes() throws ServiceLocationException {
+ return new ArrayList<String>(dAs.keySet());
+ }
+
+
+
+ /**
+ * get the next XID.
+ *
+ * @return the next XID.
+ */
+ static short nextXid() {
+ if (nextXid == 0) {
+ nextXid = 1;
+ }
+ return nextXid++;
+ }
+
+ /**
+ * find DAs for the scopes by sending a multicast service request for
+ * service <i>service:directory-agent</i>.
+ *
+ * First parameter changed from List to String[] for compatibility reasons
+ *
+ * @param scopes
+ * an <code>Array</code> of scopes.
+ * @throws ServiceLocationException
+ * in case of network errors.
+ */
+ static void daLookup(final String[] scopes) throws ServiceLocationException {
+
+ // added by Lorenz to ensure adherence to RFC2608 section 12.2.1
+ if ((System.currentTimeMillis()-lastDaLookup) < CONFIG.getConfigDaFind()){
+ // oops, too soon...
+ return;
+ }
+ receiverList = new AprDatagramAcceptor[myIPs.length];
+ try {
+ // change by TomoTherapy Inc
+ // added loop for each IP for each interface
+ // used 1.4 SocketAddress
+ // altered by Jan to be backwards compatible with Java 2
+ // changed by Lorenz to send the same message out on each interface and then wait...
+// build a ServiceRequestMessage
+ ServiceRequestMessage sreq = new ServiceRequestMessage();
+ sreq.setServiceType(new ServiceType(SLP_DA_TYPE));
+ sreq.setScopes(scopes);
+ sreq.setLocale(SLPCore.DEFAULT_LOCALE);
+ sreq.setXid(SLPCore.nextXid());
+ sreq.setMulticast(true);
+ InetSocketAddress addr = new InetSocketAddress(MCAST_ADDRESS, SLP_PORT);
+ WriteFuture[] futures = new WriteFuture[myIPs.length];
+ // send the message over each interface with the same xid
+ for (int i = 0; i < myIPs.length; i++) {
+ try {
+ platform.logTraceMessage("SENT " + sreq + "(udp multicast)");
+ ConnectFuture connFuture = senderList[i].connect(addr);
+ connFuture.await();
+ IoSession session = (AprDatagramSession) connFuture.getSession();
+ InetSocketAddress local = (InetSocketAddress) session.getLocalAddress();
+ receiverList[i] = initReceiver(local);
+ futures[i] = session.write(sreq);
+ platform.logTraceMessage("SENT (" + addr.getHostName() + ":" + addr.getPort() + ") "
+ + sreq + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()+")");
+ } catch (InterruptedException ie){
+ // what do i have to de here?
+ }
+ }
+ // make sure the unused receivers are disposed when their lifetime is up
+ setupReceiverThread(CONFIG.getWaitTime());
+ // check if they all went out
+ for (int i = 0; i < futures.length; i++) {
+ boolean success = false;
+ try {
+ // it would actually be better to wait for a total of WaitTime, not WaitTime per future...
+ success = futures[i].await(CONFIG.getWaitTime());
+ } catch (InterruptedException ie){
+ // what do i have to do here? decrement i and continue?
+ }
+ if (!success) {
+ // blacklist address
+ final List<String> remaining = new ArrayList<String>(java.util.Arrays
+ .asList(myIPs));
+ final String faulty = myIPs[i];
+ remaining.remove(faulty);
+ myIPs = (String[]) remaining.toArray(new String[remaining
+ .size()]);
+ platform.logDebug("Blacklisting IP " + faulty);
+ }
+ }
+ // don't forget to set the timestamp ;)
+ lastDaLookup = System.currentTimeMillis();
+
+ } catch (IllegalArgumentException ise) {
+ platform.logDebug("May never happen, no filter set", ise);
+ }
+ }
+
+ /**
+ * send a unicast message over TCP.
+ *
+ * @param msg
+ * the message.
+ * @return the reply.
+ * @throws ServiceLocationException
+ * in case of network errors.
+ */
+ static AbstractSLPReplyMessage sendMessageTCP(final AbstractSLPMessage msg,final InetSocketAddress addr, final boolean expectReply)
+ throws ServiceLocationException {
+ try {
+ // Debian and co. have an entry for 127.0.1.1 which leads to problems,
+ //therefor that address is changed to 127.0.0.1
+ InetSocketAddress sendAddr = addr;
+ if (addr.getAddress().getHostAddress().equals("127.0.1.1")){
+ sendAddr = new InetSocketAddress("127.0.0.1",SLP_PORT);
+ }
+ if (msg.getXid() == 0) {
+ msg.setXid(nextXid());
+ }
+ ConnectFuture future1 = tcpsender.connect(sendAddr);
+ future1.awaitUninterruptibly();
+ if (!future1.isConnected()) {
+ throw new ServiceLocationException(ServiceLocationException.NETWORK_INIT_FAILED,"Unable to open TCP socket");
+ }
+ IoSession session = future1.getSession();
+ session.write(msg);
+ platform.logTraceMessage("SENT (" + addr.getAddress().getHostAddress() + ":" + addr.getPort() + ") "
+ + msg + " (via tcp port " + ((InetSocketAddress)session.getLocalAddress()).getPort()
+ + ")");
+
+ if (!expectReply){
+ session.close(false);
+ return null;
+ }
+
+// need to wait for a reply that is handled by the receiver
+ synchronized (replyListeners){
+ List<AbstractSLPMessage> reply = (List<AbstractSLPMessage>) replyListeners.get(new Integer(msg.getXid()));
+ long start = System.currentTimeMillis();
+ while(reply.isEmpty()){
+ if (System.currentTimeMillis()-start>SLPCore.CONFIG.getWaitTime()){
+ session.close(false);
+ throw new ServiceLocationException(ServiceLocationException.NETWORK_TIMED_OUT,"Reply timed out");
+ }
+ replyListeners.wait(SLPCore.CONFIG.getWaitTime(),SLPCore.CONFIG.getWaitTime());
+ }
+ session.close(false);
+ return (AbstractSLPReplyMessage) reply.get(0);
+ }
+
+
+ } catch (Exception e) {
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_ERROR, e.getMessage());
+ }
+ }
+
+ /**
+ * send a unicast message over UDP.
+ *
+ * @param msg
+ * the message to be sent.
+ * @param addr
+ * the InetSocketAddress containing the destination address
+ * @param expectReply
+ * waits for a reply if set to true.
+ * @return the reply.
+ * @throws ServiceLocationException
+ * in case of network errors etc.
+ */
+ static AbstractSLPReplyMessage sendReliableUnicastMessage(final AbstractSLPMessage msg,final InetSocketAddress addr,
+ final boolean expectReply) throws ServiceLocationException {
+ List<AbstractSLPMessage> reply = new ArrayList<AbstractSLPMessage>();
+ if (msg.getXid() == 0) {
+ msg.setXid(nextXid());
+ }
+ if (msg.getSize() > CONFIG.getMTU() || TCP_ONLY) {
+ return sendMessageTCP(msg, addr, expectReply);
+ }
+ try {
+
+ //register this send event to catch replies
+ if (expectReply){
+ synchronized (replyListeners){
+ reply = new ArrayList<AbstractSLPMessage>();
+ replyListeners.put(new Integer(msg.getXid()), reply);
+ }
+ }
+ // Again, Debian can mess things up a bit, so we fix that here...
+ InetSocketAddress sendAddr = addr;
+ if (addr.getAddress().getHostAddress().equals("127.0.1.1")){
+ sendAddr = new InetSocketAddress("127.0.0.1",addr.getPort());
+ }
+ ConnectFuture connFuture = sender.connect(sendAddr);
+ connFuture.await(CONFIG.getDatagramMaxWait());
+ if (!connFuture.isConnected()){
+ platform.logError("Failed to send over udp: "+msg+" to "+addr.getAddress().getHostAddress()+":"+addr.getPort());
+ return null;
+ }
+ IoSession session = (AprDatagramSession) connFuture.getSession();
+ session.write(msg);
+
+ platform.logTraceMessage("SENT (" + addr.getAddress().getHostAddress() + ":" + addr.getPort() + ") "
+ + msg + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+ + ")");
+ if (!expectReply){
+ session.close(false);
+ return null;
+ }
+
+
+
+
+ // changed by Lorenz to ensure operation according to RFC2608 section 12.3
+ //need to wait for a reply that is handled by the receiver
+ synchronized (replyListeners){
+
+ reply=(List<AbstractSLPMessage>) replyListeners.get(new Integer(msg.getXid()));
+ }
+ synchronized (reply){
+ long now = System.currentTimeMillis();
+ long finalTimeout = now + CONFIG.getConfigRetryMax();
+ long waittime = CONFIG.getConfigRetry();
+ while(reply.isEmpty()){
+ if ((now=System.currentTimeMillis())>=finalTimeout){
+ return null;
+ }
+ reply.wait(waittime);
+ if (reply.isEmpty()){
+ // resend
+ if (session.isConnected()){
+ session.write(msg);
+ } else {
+ return null;
+ }
+ now = System.currentTimeMillis();
+ waittime = 2*waittime;
+ }
+ }
+ AbstractSLPReplyMessage r = (AbstractSLPReplyMessage) reply.get(0);
+ //remove the "waiting for reply" registration
+ replyListeners.remove(new Integer(msg.getXid()));
+ session.close(false);
+ return r;
+ }
+
+
+ } catch (Throwable t) {
+ if (t instanceof IllegalMonitorStateException){
+ platform.logDebug(t.getMessage(), t);
+ throw new ServiceLocationException(ServiceLocationException.NETWORK_TIMED_OUT,"Reply timed out");
+ } else {
+ platform.logDebug(t.getMessage(), t);
+ throw new ServiceLocationException((short) 1, t.getMessage());
+ }
+ }
+ }
+
+
+ /**
+ * send a unicast message over UDP.
+ *
+ * @param msg
+ * the message to be sent.
+ * @param addr
+ * the InetSocketAddress containing the destination address
+ * @param expectReply
+ * waits for a reply if set to true.
+ * @return the reply.
+ * @throws ServiceLocationException
+ * in case of network errors etc.
+ */
+ public static AbstractSLPReplyMessage sendUnicastMessage(final AbstractSLPMessage msg,final InetSocketAddress addr,
+ final boolean expectReply) throws ServiceLocationException {
+ List<AbstractSLPMessage> reply = new ArrayList<AbstractSLPMessage>();
+ if (msg.getXid() == 0) {
+ msg.setXid(nextXid());
+ }
+ if (msg.getSize() > CONFIG.getMTU() || TCP_ONLY) {
+ return sendMessageTCP(msg, addr, expectReply);
+ }
+ try {
+
+ //register this send event to catch replies
+ if (expectReply){
+ synchronized (replyListeners){
+ reply = new ArrayList<AbstractSLPMessage>();
+ replyListeners.put(new Integer(msg.getXid()), reply);
+ }
+ }
+ // Again, Debian can mess things up a bit, so we fix that here...
+ InetSocketAddress sendAddr = addr;
+ if (addr.getAddress().getHostAddress().equals("127.0.1.1")){
+ sendAddr = new InetSocketAddress("127.0.0.1",addr.getPort());
+ }
+ ConnectFuture connFuture = sender.connect(sendAddr);
+ connFuture.await(CONFIG.getDatagramMaxWait());
+ if (!connFuture.isConnected()){
+ platform.logError("Failed to send over udp: "+msg+" to "+addr.getAddress().getHostAddress()+":"+addr.getPort());
+ return null;
+ }
+ IoSession session = (AprDatagramSession) connFuture.getSession();
+ session.write(msg);
+
+ platform.logTraceMessage("SENT (" + addr.getAddress().getHostAddress() + ":" + addr.getPort() + ") "
+ + msg + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+ + ")");
+ if (!expectReply){
+ session.close(false);
+ return null;
+ }
+
+
+
+ //need to wait for a reply that is handled by the receiver
+ synchronized (replyListeners){
+
+ reply=(List<AbstractSLPMessage>) replyListeners.get(new Integer(msg.getXid()));
+ }
+ synchronized (reply){
+ long now = System.currentTimeMillis();
+ long timeout = System.currentTimeMillis()+CONFIG.getDatagramMaxWait();
+ while(reply.isEmpty()){
+ if ((now=System.currentTimeMillis())>=timeout){
+ return null;
+ }
+ reply.wait(timeout-now);
+ }
+ AbstractSLPReplyMessage r = (AbstractSLPReplyMessage) reply.get(0);
+ //remove the "waiting for reply" registration
+ replyListeners.remove(new Integer(msg.getXid()));
+ session.close(false);
+ return r;
+ }
+
+
+
+
+ } catch (Throwable t) {
+ if (t instanceof IllegalMonitorStateException){
+ platform.logDebug(t.getMessage(), t);
+ throw new ServiceLocationException(ServiceLocationException.NETWORK_TIMED_OUT,"Reply timed out");
+ } else {
+ platform.logDebug(t.getMessage(), t);
+ throw new ServiceLocationException((short) 1, t.getMessage());
+ }
+ }
+ }
+
+
+
+
+ /**
+ * send a request via multicast convergence algorithm.
+ *
+ * @param msg
+ * the message.
+ * @return the collected reply messages.
+ * @throws ServiceLocationException
+ * in case of network errors.
+ */
+ static void multicastConvergence(final ReplyFuture replyfuture,final AbstractSLPRequestMessage msg)
+ throws ServiceLocationException {
+
+ if (msg.getXid() == 0) {
+ msg.setXid(SLPCore.nextXid());
+ }
+
+ new MulticastConvergenceThread(replyfuture,msg);
+
+
+
+ }
+
+ private static boolean isLocalResponder(InetAddress addr) {
+ if (addr.getHostAddress().equals("127.0.0.1")){
+ return true;
+ }
+ for (int i = 0; i < SLPCore.myIPs.length; i++) {
+ if (addr.getHostAddress().equals(SLPCore.myIPs[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Initialize the MINA components
+ */
+ private static void initializeMina(){
+ try {
+ // initialize the UDP senders, required by both SA and UA
+ senderList=new AprDatagramConnector[myIPs.length];
+ for (int i=0;i<myIPs.length;i++){
+ AprDatagramConnector adc = new AprDatagramConnector();
+ adc.getSessionConfig().setUseReadOperation(true);
+ adc.setTtl(CONFIG.getMcastTTL());
+ adc.setMulticastInterface(myIPs[i]);
+ adc.setHandler(handler);
+ adc.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SLPProtocolCodecFactory()));
+ adc.getSessionConfig().setReuseAddress(true);
+ senderList[i]=adc;
+ }
+
+ // default sender, sends out over default multicast interface...
+ sender = new AprDatagramConnector();
+ sender.getSessionConfig().setUseReadOperation(true);
+ sender.setTtl(CONFIG.getMcastTTL());
+ sender.setHandler(handler);
+ sender.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SLPProtocolCodecFactory()));
+ sender.getSessionConfig().setReuseAddress(true);
+
+ // initialize the TCP sender (and reply-receiver...)
+ tcpsender = new AprSocketConnector();
+ tcpsender.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SLPProtocolCodecFactory()));
+ tcpsender.setHandler(handler);
+
+
+ } catch (Exception e){
+ platform.logError("[SLPCore] Unable to initialize MINA framework, aborting.", e);
+ System.out.println("[SLPCORE]: Unable to initialize MINA framework, possibly because another SLP implementation is running on the same ports");
+ }
+
+ }
+
+
+ protected static void initializeListeners() throws ServiceLocationException{
+ if (isListening){
+ return;
+ }
+ try{
+ multicastTCPAcceptor = new AprSocketAcceptor();
+ multicastTCPAcceptor.setHandler(handler);
+ multicastTCPAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SLPProtocolCodecFactory()));
+ //TODO: add thread model ?
+ multicastTCPAcceptor.setReuseAddress(true);
+ multicastTCPAcceptor.bind(new InetSocketAddress(SLPCore.SLP_PORT));
+
+
+ //set up the UDP receiver
+ multicastAcceptor = new AprDatagramAcceptor();
+ multicastAcceptor.setHandler(handler);
+ multicastAcceptor.joinGroup(SLPCore.MCAST_ADDRESS.getHostAddress());
+ multicastAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SLPProtocolCodecFactory()));
+ multicastAcceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newFixedThreadPool(10)));
+
+ DatagramSessionConfig dcfg = multicastAcceptor.getSessionConfig();
+ dcfg.setReuseAddress(true);
+ multicastAcceptor.bind(new InetSocketAddress(SLPCore.SLP_PORT));
+
+ isListening = true;
+
+ } catch (Exception e){
+ platform.logError("[SLPCore] Unable to initialize MINA acceptors.", e);
+ throw new ServiceLocationException(ServiceLocationException.NETWORK_INIT_FAILED,e.getMessage());
+ }
+
+ }
+
+
+
+ /**
+ * initialize a new receiver to listen for replies to multicast requests
+ *
+ * @param localaddress
+ * The address this receiver should listen on (unicast)
+ * @return
+ * The initialized and bound AprDatagramAcceptor
+ *
+ * @throws ServiceLocationException
+ */
+ private static AprDatagramAcceptor initReceiver(InetSocketAddress localaddress) throws ServiceLocationException {
+ AprDatagramAcceptor recv = new AprDatagramAcceptor();
+ try {
+ if (localaddress.getPort()==0){
+ //if no port is specified, listen on the default SLP port for this application
+ localaddress = new InetSocketAddress(localaddress.getAddress().getHostAddress(),SLP_PORT);
+ }
+ if (localaddress.getAddress().getHostAddress().equals("127.0.1.1")){
+ //Debian and co. have an entry in .hosts that messes things up, this line fixes that
+ localaddress = new InetSocketAddress("127.0.0.1",localaddress.getPort());
+ }
+ //initialize the UDP receiver.
+ recv.setHandler(handler);
+ recv.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SLPProtocolCodecFactory()));
+ // let each incoming packet be processed in a new thread if possible, as this acceptor
+ // deals with replies to multicast requests
+ DatagramSessionConfig dcfg = recv.getSessionConfig();
+ dcfg.setReuseAddress(true);
+ recv.bind(localaddress);
+ return recv;
+ } catch (Exception e){
+ recv.dispose();
+ throw new ServiceLocationException(ServiceLocationException.NETWORK_INIT_FAILED,"Unable to set up UDP receiver");
+ }
+ }
+
+
+
+ public static SLPDaemon getDaemon(){
+ return daemon;
+ }
+
+ public static DirectoryAgentDaemon getDirectoryAgentDaemon(){
+ return daDaemon;
+ }
+
+ public static List<String> getDas(String scope){
+ return dAs.get(scope.toLowerCase());
+ }
+
+ public static PlatformAbstraction getPlatform(){
+ return platform;
+ }
+
+ public static synchronized Map getReplyListeners(){
+ return replyListeners;
+ }
+
+
+
+ /**
+ * add a reply to the queue and notify any thread waiting for such a reply...
+ *
+ * @param msg
+ * the message to be added as a reply
+ * @param address
+ * the source address, only required for logging
+ */
+ public static synchronized void addReply(AbstractSLPMessage msg, InetSocketAddress address){
+ List<AbstractSLPMessage> queue = (List<AbstractSLPMessage>) replyListeners.get(new Integer(msg.getXid()));
+ if (queue != null) {
+ synchronized (queue) {
+ queue.add(msg);
+ queue.notifyAll();
+ }
+ return;
+ } else {
+ platform.logTraceReg("SRVREPLY recieved ("
+ + address.getAddress() + ":" + address.getPort() + ") "
+ + msg.toString()
+ + " but not replyListeners present anymore");
+ }
+ return;
+ }
+
+ /**
+ * setup a new receiver thread for DA lookup.
+ *
+ * @param minLifetime
+ * the minimum lifetime of the receiver thread.
+ */
+ private static void setupReceiverThread(final long minLifetime) {
+ new Thread("DALookupThread") {
+ public void run() {
+ platform.logDebug("[DALOOKUP]: Thread starting with lifetime " + minLifetime);
+
+ // calculate the end of lifetime
+ long timeout = System.currentTimeMillis() + minLifetime+1000;
+ long now;
+
+ // while lifetime is not expired
+ while ((now=System.currentTimeMillis()) < timeout) {
+ try {
+ long remain = timeout-now;
+ Thread.sleep(remain);
+ } catch (InterruptedException ie){
+ continue;
+ }
+ }
+ for (int i=0;i<receiverList.length;i++){
+ receiverList[i].dispose();
+ }
+ platform.logDebug("[DALOOKUP]: Thread stopping after " + minLifetime);
+ }
+ }.start();
+ }
+
+ private static class MulticastConvergenceThread extends Thread {
+
+
+ private final ReplyFuture replyfuture;
+ private final AbstractSLPRequestMessage msg;
+
+ public MulticastConvergenceThread(ReplyFuture rf,AbstractSLPRequestMessage req){
+ super("MulticastConvergenceThread");
+ replyfuture=rf;
+ msg=req;
+ start();
+ }
+
+
+ public void run() {
+ //System.out.println("Entering MCC Algorithm...");
+// One receiver for each interface on which mulitcast requests are sent
+ AprDatagramAcceptor[] recv = new AprDatagramAcceptor[myIPs.length];
+ AprDatagramSession[] sessions = new AprDatagramSession[myIPs.length];
+// number of interfaces that don't work correctly
+ int failedInterfaces = 0;
+ try {
+
+ long start = System.currentTimeMillis();
+
+ List<AbstractSLPMessage> replyQueue = new ArrayList<AbstractSLPMessage>();
+ List<String> responders = new ArrayList<String>();
+ if (msg.getPrevResponders()!=null){
+ for (String r : msg.getPrevResponders()){
+ responders.add(r);
+ }
+ }
+ List<String> responses = new ArrayList<String>();
+
+ if (msg.getXid() == 0) {
+ msg.setXid(SLPCore.nextXid());
+ }
+
+ // register the reply queue as listener
+ Integer queryXID = new Integer(msg.getXid());
+ synchronized (replyListeners) {
+ replyListeners.put(queryXID, replyQueue);
+ }
+
+
+
+ // send to localhost, in case the OS does not support multicast over
+ // loopback which can fail if no SA is running locally
+ try {
+ InetSocketAddress local = new InetSocketAddress(LOCALHOST.getHostAddress(),SLP_PORT);
+ replyQueue.add(sendMessageTCP(msg,local,true));
+ } catch (ServiceLocationException e) {
+
+ }
+ msg.setMulticast(true);
+ InetSocketAddress remoteaddr = new InetSocketAddress(MCAST_ADDRESS.getHostAddress(),SLP_PORT);
+
+ AbstractSLPReplyMessage reply;
+
+
+ for (int i = 0; i < myIPs.length; i++) {
+ try {
+ // initialize the sessions and the receivers
+ InetSocketAddress localaddr = new InetSocketAddress(myIPs[i],0);
+
+ ConnectFuture connFuture = senderList[i].connect(remoteaddr);
+ try {
+ connFuture.await(CONFIG.getDatagramMaxWait());
+ } catch (InterruptedException ie){
+
+ }
+ if (!connFuture.isConnected()){
+ platform.logError("Failed to send over udp: "+msg+" to "+remoteaddr.getAddress().getHostAddress()+":"+remoteaddr.getPort());
+ i--;
+ failedInterfaces++;
+ continue;
+ }
+ sessions[i] = (AprDatagramSession) connFuture.getSession();
+ localaddr = new InetSocketAddress(myIPs[i],((InetSocketAddress)sessions[i].getLocalAddress()).getPort());
+
+ recv[i] = initReceiver(localaddr);
+ } catch (ServiceLocationException sle){
+ // the receiver for this interface couldn't get started...
+ failedInterfaces++;
+ i--;
+ continue;
+ }
+
+ }
+
+
+ // the multicast convergence algorithm
+ long totalTimeout = System.currentTimeMillis()
+ + CONFIG.getMcastMaxWait();
+ int[] transmissionSchedule = SLPCore.CONFIG.getMcastTimeouts();
+ int retryCounter = 0;
+ long nextTimeout;
+ int failCounter = 0;
+ boolean seenNew = false;
+ boolean seenLocalResponse = false;
+ nextTimeout = System.currentTimeMillis()
+ + transmissionSchedule[retryCounter];
+
+ while (!Thread.currentThread().isInterrupted()
+ && totalTimeout > System.currentTimeMillis()
+ && nextTimeout > System.currentTimeMillis()
+ && retryCounter < transmissionSchedule.length
+ && failCounter < CONFIG.getConvergenceFailerCount()) {
+ platform.logDebug("[MCC]: starting round " + retryCounter);
+ //System.out.println("Entering round "+retryCounter);
+ msg.setPrevResponders((String[]) responders.toArray(new String[]{}));
+
+ // finish convergence in case of message size exeeds MTU
+ if (msg.getSize() > CONFIG.getMTU()) {
+ for (int i=0;i<sessions.length-failedInterfaces;i++){
+ sessions[i].close(true);
+ recv[i].dispose();
+ replyfuture.setDone(msg.getScopes(),false);
+ }
+ break;
+ }
+
+
+ if (msg.getSize() > CONFIG.getMTU() || TCP_ONLY) {
+ try {
+ sendMessageTCP(msg, remoteaddr, false);
+ } catch (ServiceLocationException sle){
+ //couldn't send message over tcp...
+ }
+ }
+ for (int i = 0; i < sessions.length-failedInterfaces; i++){
+ sessions[i].write(msg);
+ platform.logTraceMessage("SENT " + msg + " on interface " + myIPs[i]);
+ }
+
+ /**
+ * @fix: bug #1518729. Changed processing of the replyQueue.
+ * Thanks to Richard Reid for figuring out the problem
+ * with multicast replies and proposing the fix
+ */
+ try {
+ Thread.sleep(transmissionSchedule[retryCounter]);
+ } catch (InterruptedException dontcare) {
+ // Restore the interrupted status
+ Thread.currentThread().interrupt();
+ }
+
+ synchronized (replyQueue) {
+ // did something else wake us up ?
+ if (replyQueue.isEmpty()) {
+ failCounter++;
+ nextTimeout = System.currentTimeMillis()
+ + transmissionSchedule[retryCounter++];
+ continue;
+ }
+ while (!replyQueue.isEmpty()) {
+ reply = (AbstractSLPReplyMessage) replyQueue.remove(0);
+ // silently drop duplicate responses, process only new results
+ if (!responders.contains(reply.getSource())) {
+ if (isLocalResponder(InetAddress.getByName(reply.getSource()))) {
+ if (seenLocalResponse) {
+ continue;
+ } else {
+ seenLocalResponse = true;
+ }
+ }
+ seenNew = true;
+ responders.add(reply.getSource());
+ responses.addAll(reply.getResultAsList());
+ replyfuture.add(reply);
+
+
+ }
+ }
+
+ if (!seenNew) {
+ failCounter++;
+ } else {
+ seenNew = false;
+ }
+ }
+ nextTimeout = System.currentTimeMillis()
+ + transmissionSchedule[retryCounter++];
+ }
+ for (int i=0;i<sessions.length-failedInterfaces;i++){
+ sessions[i].close(true);
+ recv[i].dispose();
+ }
+
+
+ // we are done, remove the listener queue
+ synchronized (replyListeners) {
+ replyListeners.remove(queryXID);
+ }
+
+ platform.logDebug("convergence for xid=" + msg.getXid()
+ + " finished after "
+ + (System.currentTimeMillis() - start)
+ + " ms, result: " + responses);
+
+ replyfuture.setDone(msg.getScopes(),false);
+ } catch (IOException ioe) {
+ for (int i=0;i<recv.length-failedInterfaces;i++){
+ sessions[i].close(true);
+ recv[i].dispose();
+ //replyfuture.setDone();
+ }
+
+ platform.logDebug(ioe.getMessage(), ioe);
+ }
+
+ }
+
+
+
+
+ }
+
+ public static void shutdownCore(){
+ if (daDaemon!=null){
+ daDaemon.shutdown();
+ }
+ if (daemon!=null){
+ shutdownAdvertiser();
+ }
+
+ }
+
+
+}
Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPCore.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemon.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemon.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemon.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemon.java Tue Jun 9 12:00:29 2009
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.slp.impl;
+
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.messages.AbstractSLPMessage;
+import org.apache.directory.slp.messages.AbstractSLPReplyMessage;
+import org.apache.directory.slp.messages.DAAdvertisementMessage;
+
+
+
+
+
+/**
+ * the SLPDeaemon interface. Factored out to make the daemon part optional as
+ * part of the jSLP modularity.
+ *
+ * @author Jan S. Rellermeyer
+ */
+public interface SLPDaemon {
+
+ /**
+ * called, when a new DA has been discovered.
+ *
+ * @param advert
+ * the <code>DAAdvertisement</code> received from the new DA.
+ */
+ void newDaDiscovered(DAAdvertisementMessage advert);
+
+ /**
+ * handle a message dispatched by SLPCore.
+ *
+ * @param msg
+ * the message.
+ * @return the reply message or <code>null</code>.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ */
+ AbstractSLPReplyMessage handleMessage(final AbstractSLPMessage msg)
+ throws ServiceLocationException;
+
+}
Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemon.java
------------------------------------------------------------------------------
svn:mime-type = text/plain