Return-Path: Delivered-To: apmail-directory-commits-archive@www.apache.org Received: (qmail 64340 invoked from network); 9 Jun 2009 12:00:53 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 9 Jun 2009 12:00:53 -0000 Received: (qmail 48582 invoked by uid 500); 9 Jun 2009 12:01:04 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 48468 invoked by uid 500); 9 Jun 2009 12:01:04 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 48449 invoked by uid 99); 9 Jun 2009 12:01:04 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 09 Jun 2009 12:01:04 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 09 Jun 2009 12:00:56 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 3C0662388906; Tue, 9 Jun 2009 12:00:35 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r782968 [5/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... Date: Tue, 09 Jun 2009 12:00:32 -0000 To: commits@directory.apache.org From: rjan@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090609120035.3C0662388906@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java?rev=782968&view=auto ============================================================================== --- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java (added) +++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java Tue Jun 9 12:00:29 2009 @@ -0,0 +1,1108 @@ +/* + * 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.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.directory.slp.Service; +import org.apache.directory.slp.ServiceLocationException; +import org.apache.directory.slp.ServiceType; +import org.apache.directory.slp.ServiceURL; +import org.apache.directory.slp.extensions.AbstractExtension; +import org.apache.directory.slp.extensions.AttributeListExtension; +import org.apache.directory.slp.impl.filter.Filter; +import org.apache.directory.slp.messages.AbstractSLPMessage; +import org.apache.directory.slp.messages.AbstractSLPReplyMessage; +import org.apache.directory.slp.messages.AttributeReplyMessage; +import org.apache.directory.slp.messages.AttributeRequestMessage; +import org.apache.directory.slp.messages.DAAdvertisementMessage; +import org.apache.directory.slp.messages.ServiceAcknowledgementMessage; +import org.apache.directory.slp.messages.ServiceDeregistrationMessage; +import org.apache.directory.slp.messages.ServiceRegistrationMessage; +import org.apache.directory.slp.messages.ServiceReplyMessage; +import org.apache.directory.slp.messages.ServiceRequestMessage; +import org.apache.directory.slp.messages.ServiceTypeReplyMessage; +import org.apache.directory.slp.messages.ServiceTypeRequestMessage; + +/** + * the jSLP daemon class. This class is only required, if the peer is configured + * as a SA and no other SLP daemon is running on the machine. UA-only + * configurations or distributions that are intended to run on a machine with + * OpenSLP slpd can be packaged without this class. + * + * @author Jan S. Rellermeyer + */ +public final class SLPDaemonImpl implements SLPDaemon { + + /** + * thread loop variable. + */ + private boolean running = true; + + /** + * Map of registered services: + * + * String scope -> List of ServiceURLs services. //?? Service, not URLS... + */ + private Map> registeredServices = new HashMap>(); + + /** + * Sorted set for disposal of services which lifetimes have expired: + * + * Long expirationTimestamp -> ServiceURL service. + */ + private SortedMap serviceDisposalQueue = new TreeMap(); + + + + + /** + * create a new SLPDaemon instance. + * + * @throws Exception + * if something goes wrong. + */ + public SLPDaemonImpl() throws Exception { + new ServiceDisposalThread(); + SLPCore.platform.logDebug("jSLP daemon starting ..."); + running=true; + } + + /** + * register a service with the SLP framework. For the scopes, where DAs are + * known, the service will be registered with all DAs. + * + * @param reg + * the ServiceRegistration. + */ + private void registerService(final ServiceRegistrationMessage reg) { + // prevent registrations from being sent to the same DA multiple times when in multiple scopes + List handledDAs = new ArrayList(); + + Service service = new Service(reg); + String[] scopes = reg.getScopes(); + for (int i=0;i ServiceURL.LIFETIME_PERMANENT) { + synchronized (serviceDisposalQueue) { + long next = System.currentTimeMillis() + + (reg.getServiceURL().getLifetime() * 1000); + ArrayList keys = new ArrayList(serviceDisposalQueue + .keySet()); + for (Iterator iter = keys.iterator(); iter.hasNext();) { + Object key = iter.next(); + if (serviceDisposalQueue.get(key).equals(reg.getServiceURL())) { + serviceDisposalQueue.remove(key); + } + } + serviceDisposalQueue.put(new Long(next), reg.getServiceURL()); + serviceDisposalQueue.notifyAll(); + } + } + + SLPCore.platform.logTraceReg("REGISTERED " + reg.getServiceURL()); + + // register the service with all known DAs in the scopes + List daList = (List) SLPCore.dAs.get(scope); + + // no DA for the scope known ? + // try to find one + //could this lead to unnecessary timeouts??? + if ((daList == null || daList.isEmpty()) && !SLPCore.noDiscovery) { + try { + SLPCore.daLookup(new String[] { (String) scope }); + + // wait a short time for incoming replies + synchronized (SLPCore.dAs) { + try { + SLPCore.dAs.wait(SLPCore.CONFIG.getWaitTime()); + } catch (InterruptedException e) { + } + } + daList = SLPCore.dAs.get(scope); + } catch (ServiceLocationException sle) { + SLPCore.platform.logError(sle.getMessage(), sle + .fillInStackTrace()); + } + } + + + + + if (daList != null && !daList.isEmpty()) { + final String[] dAs = (String[]) daList + .toArray(new String[daList.size()]); + for (int j = 0; j < dAs.length; j++) { + try{ + if (handledDAs.contains(dAs[j])){ + continue; + } + handledDAs.add(dAs[j]); + // if the ip is within the framework, i.e. DA and SA are running at the same time, then pass the reg on internally + if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dAs[j])){ + if (SLPCore.getDirectoryAgentDaemon()!=null){ + if (SLPCore.getDirectoryAgentDaemon().isKnownService(service)){ + SLPCore.getDirectoryAgentDaemon().updateServiceEntry(reg); + } else { + SLPCore.getDirectoryAgentDaemon().registerService(reg); + } + } else { + // what? no daDaemon running?? must remove the ip from the list + SLPUtils.removeValueFromAll(SLPCore.dAs, (reg).getServiceURL().toString()); + SLPCore.dASPIs.remove((reg).getServiceURL().toString()); + + } + } else { + announceService(dAs[j], reg); + } + + } catch (ServiceLocationException e) { + if (e.getErrorCode()==ServiceLocationException.INVALID_REGISTRATION){ + return; + } + + // remove DA from list + SLPUtils.removeValueFromAll(SLPCore.dAs, dAs[i]); + SLPCore.dASPIs.remove(dAs[i]); + SLPCore.platform.logError(e.getMessage(), e + .fillInStackTrace()); + } + } + } + } + + } + + private void updateService(final ServiceRegistrationMessage reg) throws ServiceLocationException{ + + // fresh flag is set and the message comes from the framework, considered safe for now... + Service registeredService = null; + Service newService = new Service(reg); + boolean found = false; + for (int i=0;i services = registeredServices.get(reg.getScopes()[i].toLowerCase().trim()); + if (services == null) { + continue; + } + + for (Iterator srvs = services.iterator(); srvs.hasNext();) { + Service service = srvs.next(); + if (service.getURL().toString().equals(reg.getServiceURL().toString())){ + registeredService = service; + found = true; + break; + } + } + } + + if (registeredService==null){ + throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE,"No service to update..."); + } + + Dictionary registeredAttributes = registeredService.getAttributes(); + Dictionary newAttributes = SLPUtils.stringArrayToDict(reg.getAttrList()); + Enumeration keys = newAttributes.keys(); + while (keys.hasMoreElements()){ + String key = keys.nextElement(); + registeredAttributes.remove(key); + registeredAttributes.put(key, newAttributes.get(key)); + } + newService.setAttributes(registeredAttributes); + + final String[] scopes = (String[]) registeredServices.keySet().toArray( + new String[registeredServices.size()]); + for (int i = 0; i < scopes.length; i++) { + final List tmp = registeredServices.get(scopes[i].toLowerCase()); + final Service[] services = tmp.toArray(new Service[tmp + .size()]); + + for (int j = 0; j < services.length; j++) { + if (reg.getServiceURL().matches(services[j].getURL())) { + List daList = SLPCore.dAs.get(scopes[i].toLowerCase()); + if (daList != null) { + for (String dA : daList) { + + // if there is a local DA in the same framework, deregister the service directly from there + if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dA)){ + if (SLPCore.getDirectoryAgentDaemon()!=null){ + SLPCore.getDirectoryAgentDaemon().updateServiceEntry(reg); + } else { + // what? no daDaemon running?? must remove the ip from the list + SLPUtils.removeValueFromAll(SLPCore.dAs, dA); + SLPCore.dASPIs.remove(dA); + + } + return; + } + + // update all known remote DAs + + + if (SLPCore.CONFIG.getSecurityEnabled()) { + List spiList = (List) SLPCore.dASPIs + .get(dA); + reg.sign(SLPUtils.listToStringArray(spiList)); + } + + announceUpdatedService(dA, reg, newService); + + + } + } + + synchronized (registeredServices) { + SLPUtils.removeValue(registeredServices, scopes[i], + services[j]); + SLPUtils.addValue(registeredServices, scopes[i], newService); + } + break; + } + } + } + } + + + + /** + * deregister a service from the SLP framework. Deregisters from all DAs + * within the scopes and from the local service cache. + * + * @param dereg + * the service deregistration. + * @throws ServiceLocationException + */ + private void deregisterService(final ServiceDeregistrationMessage dereg) + throws ServiceLocationException { + + final String[] scopes = (String[]) registeredServices.keySet().toArray( + new String[registeredServices.size()]); + List handledDAs = new ArrayList(); + for (int i = 0; i < scopes.length; i++) { + final List tmp = registeredServices.get(scopes[i].toLowerCase()); + final Service[] services = tmp.toArray(new Service[tmp + .size()]); + + for (int j = 0; j < services.length; j++) { + if (dereg.getServiceURL().matches(services[j].getURL())) { + List daList = SLPCore.dAs.get(scopes[i].toLowerCase()); + if (daList != null) { + for (String dA : daList) { + if (handledDAs.contains(dA)){ + continue; + } + handledDAs.add(dA); + try { + // if there is a local DA in the same framework, deregister the service directly from there + if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dA)){ + if (SLPCore.getDirectoryAgentDaemon()!=null){ + SLPCore.getDirectoryAgentDaemon().deregisterService(dereg); + } else { + // what? no daDaemon running?? must remove the ip from the list + SLPUtils.removeValueFromAll(SLPCore.dAs, (dereg).getServiceURL().toString()); + SLPCore.dASPIs.remove((dereg).getServiceURL().toString()); + + } + return; + } + + // deregister from all known remote DAs + + ServiceDeregistrationMessage dadereg = new ServiceDeregistrationMessage(); + dadereg.setLocale(dereg.getLocale()); + dadereg.setMulticast(false); + dadereg.setScopes(dereg.getScopes()); + dadereg.setServiceURL(dereg.getServiceURL()); + dadereg.setTags(dereg.getTags()); + + InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(dA),SLPCore.SLP_PORT); + dadereg.setXid(SLPCore.nextXid()); + if (SLPCore.CONFIG.getSecurityEnabled()) { + List spiList = (List) SLPCore.dASPIs + .get(dA); + dadereg.sign(spiList); + } + AbstractSLPReplyMessage reply = new ServiceReplyMessage(); + new AnnouncerThread(address,dadereg,reply); + + } catch (UnknownHostException uhe) { + throw new ServiceLocationException( + ServiceLocationException.NETWORK_ERROR, + uhe.getMessage()); + } + } + } + synchronized (registeredServices) { + SLPUtils.removeValue(registeredServices, scopes[i], + services[j]); + } + break; + } + } + } + } + + /** + * all incoming messages are handled here. + * + * @param msg + * the message to be processed. + * @return the reply if the handled message came in via TCP. Otherwise null + * will be returned. + * @throws ServiceLocationException + * for various reasons like authentication failures etc. + */ + public AbstractSLPReplyMessage handleMessage(final AbstractSLPMessage msg) + throws ServiceLocationException { + short zero=0; + if (msg == null) { + return null; + } + + String via = msg.isTcp() ? " (tcp)" : " (udp)"; + + SLPCore.platform.logTraceMessage("RECEIVED (" + msg.getSource() + ":" + + msg.getPort() + ") " + msg.toString() + via); + + AbstractSLPReplyMessage reply = null; + + switch (msg.getFuncID()) { + case AbstractSLPMessage.SRVRQST: + if (msg.hasUnsupportedMandatoryExtensions()){ + ServiceReplyMessage servreply = new ServiceReplyMessage(); + servreply.setXid(msg.getXid()); + servreply.setLocale(msg.getLocale()); + servreply.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD); + return servreply; + } + ServiceRequestMessage req = (ServiceRequestMessage) msg; + + List results = new ArrayList(); + List extensions = new ArrayList(); + for (int i=0;i services = registeredServices.get(req.getScopes()[i].toLowerCase()); + if (services == null) { + continue; + } + + for (Service service : services) { + if (service.getURL().getServiceType().matches(req.getServiceType())) { + if (req.getPredicate() == null || req.getPredicate().equals("")) { + results.add(service.getURL()); + if (req.hasExtensionType(AbstractExtension.ATTRIBUTE_LIST_EXTENSION)){ + AttributeListExtension ale = new AttributeListExtension(service.getURL().toString(),SLPUtils.dictToString(service.getAttributesAsStringDict())); + extensions.add(ale); + } + continue; + } + Filter filter = SLPCore.platform.createFilter(req.getPredicate()); + if (filter.match(service.getAttributes())) { + results.add(service.getURL()); + if (req.hasExtensionType(AbstractExtension.ATTRIBUTE_LIST_EXTENSION)){ + AttributeListExtension ale = new AttributeListExtension(service.getURL().toString(),SLPUtils.dictToString(service.getAttributesAsStringDict())); + extensions.add(ale); + } + } + } + } + } + + /* + * if there is no result, don't send a reply. This causes the SA to + * get the same message at least two more times but the RFC strictly + * demands this for multicast requests + */ + if (results.size() == 0 && req.isMulticast()) { + return null; + } + + reply = new ServiceReplyMessage(); + ServiceReplyMessage servreply = (ServiceReplyMessage) reply; + servreply.setXid(req.getXid()); + servreply.setLocale(req.getLocale()); + servreply.setErrorCode(zero); + servreply.setServiceURLs((ServiceURL[]) results.toArray(new ServiceURL[]{})); + + servreply.setExtensions(extensions.toArray(new AbstractExtension[]{})); + + if (SLPCore.CONFIG.getSecurityEnabled()) { + servreply.sign(SLPUtils.arrayToString(req.getSPIs(),",")); + } + + return servreply; + + case AbstractSLPMessage.ATTRRQST: + if (msg.hasUnsupportedMandatoryExtensions()){ + AttributeReplyMessage attreply = new AttributeReplyMessage(); + attreply.setXid(msg.getXid()); + attreply.setLocale(msg.getLocale()); + attreply.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD); + return attreply; + } + + + AttributeRequestMessage attreq = (AttributeRequestMessage) msg; + + // moved this out of the for loop for performance + // the request can either be for a ServiceURL or a ServiceType + Object reqService; + boolean fullurl = false; + if ((attreq.getServiceUrl().getURL().indexOf("//") == -1) || (attreq.getServiceUrl().getHost().equals("nullnull"))) { + reqService = attreq.getServiceUrl().getServiceType(); + } else { + fullurl = true; + reqService = new ServiceURL(attreq.getServiceUrl().getURL(), 0); + } + + List attResult = new ArrayList(); + for (int i=0;i services = registeredServices.get(attreq.getScopes()[i].toLowerCase()); + if (services == null) { + continue; + } + + + // if spi is sent, the request must be for a full url and + // the tag list has to be empty + if (attreq.getSPIs().length==0 + || (fullurl && attreq.getTags().length==0)) { + for (Service service:services) { + if (service.getURL().matches(reqService)) { + attResult.addAll(SLPUtils.findMatches( + SLPUtils.arrayToList(attreq.getTags()), service.getAttributesAsStringDict())); + } + } + } + } + + String[] finalAtts = SLPUtils.listToStringArray(attResult); + if (!fullurl){ + finalAtts = SLPUtils.mergeAttributes(attResult); + } + + reply = new AttributeReplyMessage(); + AttributeReplyMessage attrep = (AttributeReplyMessage) reply; + attrep.setAttributes(finalAtts); + attrep.setLocale(attreq.getLocale()); + attrep.setXid(attreq.getXid()); + attrep.setAuthBlocks(new AuthenticationBlock[0]); + attrep.setErrorCode(zero); + if (attreq.getSPIs().length>0 && !fullurl){ + attrep.setErrorCode(ServiceLocationException.AUTHENTICATION_FAILED); + } + + + + if (SLPCore.CONFIG.getSecurityEnabled()) { + attrep.sign(SLPUtils.arrayToString(attreq.getSPIs(),",")); + } + return reply; + case AbstractSLPMessage.SRVTYPERQST: + + if (msg.hasUnsupportedMandatoryExtensions()){ + ServiceTypeReplyMessage streply = new ServiceTypeReplyMessage(); + streply.setXid(msg.getXid()); + streply.setLocale(msg.getLocale()); + streply.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD); + return streply; + } + + ServiceTypeRequestMessage streq = (ServiceTypeRequestMessage) msg; + + ArrayList result = new ArrayList(); + + // iterate over scopes + for (int i=0;i0){ + deleteAttributes(dereg); + } else { + deregisterService(dereg); + } + + reply = new ServiceAcknowledgementMessage(); + srvreply = (ServiceAcknowledgementMessage) reply; + srvreply.setXid(msg.getXid()); + srvreply.setErrorCode(zero); + srvreply.setLocale(msg.getLocale()); + return srvreply; + + case AbstractSLPMessage.SRVACK: + if (msg.hasUnsupportedMandatoryExtensions()){ + return null; + } + final AbstractSLPReplyMessage rep = (AbstractSLPReplyMessage) msg; + if (rep.getErrorCode() != 0) { + SLPCore.platform.logWarning(msg.getSource() + + " replied with error code " + rep.getErrorCode() + + " (" + rep + ")"); + } + SLPCore.addReply(msg, new InetSocketAddress(msg.getSource(),msg.getPort())); + return null; + + default: + // this should never happen, message should already cause an + // exception during parsing + throw new ServiceLocationException( + ServiceLocationException.NOT_IMPLEMENTED, + "The message type " + AbstractSLPMessage.getType(msg.getFuncID()) + + " is not implemented"); + } + + } + + /** + * get informed about a new discovered DA. Registers all services in the + * scopes of the new DA. + * + * @param advert + * the DA advertisement. + */ + public void newDaDiscovered(final DAAdvertisementMessage advert) { + // so find all services within the scopes of the new DA: + for (int i=0;i> getRegisteredServices(){ + return registeredServices; + } + + + + /** + * Delete attributes from an existing regstration + * + * @param dereg + * The Deregistration Message asking for this to happen + * @throws ServiceLocationException + */ + private void deleteAttributes(ServiceDeregistrationMessage dereg) throws ServiceLocationException{ + // check for security has been done by the handler! + // message comes from the framework, considered safe for now... + Service registeredService = null; + boolean found = false; + for (int i=0;i services = registeredServices.get(dereg.getScopes()[i].toLowerCase().trim()); + if (services == null) { + continue; + } + + for (Iterator srvs = services.iterator(); srvs.hasNext();) { + Service service = srvs.next(); + if (service.getURL().toString().equals(dereg.getServiceURL().toString())){ + registeredService = service; + found = true; + break; + } + } + } + + if (registeredService==null){ + throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE,"No service to update..."); + } + + Dictionary registeredAttributes = registeredService.getAttributes(); + for (String t: dereg.getTags()){ + registeredAttributes.remove(t); + } + + // now propagate to DAs + + final String[] scopes = (String[]) registeredServices.keySet().toArray( + new String[registeredServices.size()]); + for (int i = 0; i < scopes.length; i++) { + final List tmp = registeredServices.get(scopes[i].toLowerCase()); + final Service[] services = tmp.toArray(new Service[tmp + .size()]); + + for (int j = 0; j < services.length; j++) { + if (dereg.getServiceURL().matches(services[j].getURL())) { + List daList = SLPCore.dAs.get(scopes[i].toLowerCase()); + if (daList != null) { + for (String dA : daList) { + + // if there is a local DA in the same framework, delete the attribute directly from there + if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dA)){ + if (SLPCore.getDirectoryAgentDaemon()!=null){ + SLPCore.getDirectoryAgentDaemon().deregisterService(dereg); + } else { + // what? no daDaemon running?? must remove the ip from the list + SLPUtils.removeValueFromAll(SLPCore.dAs, dA); + SLPCore.dASPIs.remove(dA); + + } + return; + } + +// deregister from all known remote DAs + + ServiceDeregistrationMessage dadereg = new ServiceDeregistrationMessage(); + dadereg.setLocale(dereg.getLocale()); + dadereg.setMulticast(false); + dadereg.setScopes(dereg.getScopes()); + dadereg.setServiceURL(dereg.getServiceURL()); + dadereg.setTags(dereg.getTags()); + + try { + InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(dA),SLPCore.SLP_PORT); + dadereg.setXid(SLPCore.nextXid()); + AbstractSLPReplyMessage reply = new ServiceReplyMessage(); + new AnnouncerThread(address,dadereg,reply); + } catch (UnknownHostException uhe) { + throw new ServiceLocationException( + ServiceLocationException.NETWORK_ERROR, + uhe.getMessage()); + } + + + + + + } + } + + // now that we have found a service that matches the one in dereg, we can move on to the next scope + break; + } + } + } + } + + + + + + + /** + * register a service with a DA. + * + * @param dAAddress + * the IP address of the DA as String + * @param reg + * the ServiceRegistration message. + * @throws ServiceLocationException + * in case of network errors. + */ + private void announceService(final String dAAddress, + final ServiceRegistrationMessage reg) throws ServiceLocationException { + try { + InetSocketAddress addr = new InetSocketAddress(InetAddress.getByName(dAAddress),SLPCore.SLP_PORT); + ServiceRegistrationMessage dareg = new ServiceRegistrationMessage(); + dareg.setAttrList(reg.getAttrList()); + dareg.setAuthBlocks(reg.getAuthBlocks()); + dareg.setLocale(reg.getLocale()); + dareg.setMulticast(false); + dareg.setScopes(reg.getScopes()); + dareg.setServiceType(reg.getServiceType()); + dareg.setServiceURL(reg.getServiceURL()); + dareg.setXid(SLPCore.nextXid()); + dareg.setFresh(reg.isFresh()); + if (SLPCore.CONFIG.getSecurityEnabled()) { + List spiList = SLPCore.dASPIs.get(dAAddress); + dareg.sign((String[]) spiList.toArray(new String[]{})); + } + new AnnouncerThread(addr,dareg,null); + + } catch (UnknownHostException e) { + SLPCore.platform.logError("Service announcement to " + + dAAddress + " failed. ", e.fillInStackTrace()); + } + } + + + /** + * updatea service with a DA. + * + * @param dAAddress + * the IP address of the DA as String + * @param reg + * the ServiceRegistration message. + * @throws ServiceLocationException + * in case of network errors. + */ + private void announceUpdatedService(final String dAAddress, + final ServiceRegistrationMessage reg, final Service service) throws ServiceLocationException { + try { + InetSocketAddress addr = new InetSocketAddress(InetAddress.getByName(dAAddress),SLPCore.SLP_PORT); + ServiceRegistrationMessage dareg = new ServiceRegistrationMessage(); + dareg.setAttrList(reg.getAttrList()); + dareg.setAuthBlocks(reg.getAuthBlocks()); + dareg.setLocale(reg.getLocale()); + dareg.setMulticast(false); + dareg.setScopes(reg.getScopes()); + dareg.setServiceType(reg.getServiceType()); + dareg.setServiceURL(reg.getServiceURL()); + dareg.setXid(SLPCore.nextXid()); + dareg.setFresh(reg.isFresh()); + if (SLPCore.CONFIG.getSecurityEnabled()) { + List spiList = SLPCore.dASPIs.get(dAAddress); + dareg.sign((String[]) spiList.toArray(new String[]{})); + } + new UpdaterThread(addr,dareg,service); + + } catch (UnknownHostException e) { + SLPCore.platform.logError("Service announcement to " + + dAAddress + " failed. ", e.fillInStackTrace()); + } + } + + + + + + + + + /** + * service disposal thread. Removes services from the local registry when + * their lifetime has expired. + */ + private final class ServiceDisposalThread extends Thread { + + /** + * create and start a new instance of this thread. + * + */ + private ServiceDisposalThread() { + start(); + } + + /** + * thread's main loop. + */ + public void run() { + try { + while (running) { + synchronized (serviceDisposalQueue) { + if (serviceDisposalQueue.isEmpty()) { + // nothing to do, sleep until something arrives + SLPCore.platform + .logDebug("ServiceDisposalThread sleeping ..."); + serviceDisposalQueue.wait(); + } else { + // we have work, do everything that is due + Long nextActivity; + while (!serviceDisposalQueue.isEmpty() + && (nextActivity = ((Long) serviceDisposalQueue + .firstKey())).longValue() <= System + .currentTimeMillis()) { + + ServiceURL service = (ServiceURL) serviceDisposalQueue + .get(nextActivity); + + ServiceDeregistrationMessage dereg = new ServiceDeregistrationMessage(); + dereg.setServiceURL(service); + dereg.setLocale(SLPCore.DEFAULT_LOCALE); + + try { + deregisterService(dereg); + } catch (ServiceLocationException sle) { + SLPCore.platform.logError(sle + .getMessage(), sle + .fillInStackTrace()); + } + SLPCore.platform + .logTraceReg("disposed service " + + service); + serviceDisposalQueue.remove(nextActivity); + } + if (!serviceDisposalQueue.isEmpty()) { + /* + * there are some activities in the future, + * sleep until the first activity becomes due + */ + nextActivity = ((Long) serviceDisposalQueue + .firstKey()); + long waitTime = nextActivity.longValue() + - System.currentTimeMillis(); + if (waitTime > 0) { + SLPCore.platform + .logDebug("sleeping for " + + waitTime / 1000 + + " seconds."); + serviceDisposalQueue.wait(waitTime); + } + } + } + } + } + } catch (InterruptedException ie) { + // let the thread stop. + } + } + } + + + + /** + * service anouncer thread. + */ + private final class AnnouncerThread extends Thread { + + + private InetSocketAddress addr; + private AbstractSLPMessage msg; + private AbstractSLPReplyMessage replyMsg; + + private AnnouncerThread(InetSocketAddress sock,final AbstractSLPMessage message, AbstractSLPReplyMessage reply) { + addr=sock; + msg=message; + if (reply!=null){ + replyMsg=reply; + } else { + replyMsg = new ServiceReplyMessage(); + } + start(); + } + + /** + * thread's main loop. + */ + public void run() { + try{ + AbstractSLPReplyMessage rm = SLPCore.sendReliableUnicastMessage(msg, addr, true); + if (rm!=null){ + replyMsg.setErrorCode(rm.getErrorCode()); + } else { + + //remove DA from list + SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress()); + SLPCore.dASPIs.remove( addr.getAddress().getHostAddress()); + } + + if (msg instanceof ServiceRegistrationMessage){ + SLPCore.platform.logTraceReg("ANNOUNCED " + + ((ServiceRegistrationMessage)msg).getServiceURL() + " to " + addr.getAddress().getHostAddress()); + } else if (msg instanceof ServiceDeregistrationMessage){ + SLPCore.platform.logTraceReg("DEREGISTERED " + + ((ServiceDeregistrationMessage)msg).getServiceURL() + " from " + addr.getAddress().getHostAddress()); + } + + } catch (ServiceLocationException sle){ + if (msg instanceof ServiceRegistrationMessage){ + // remove DA from list + SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress()); + SLPCore.dASPIs.remove( addr.getAddress().getHostAddress()); + SLPCore.platform.logError(sle.getMessage(), sle.fillInStackTrace()); + } + } + } + } + + + /** + * service anouncer thread. + */ + private final class UpdaterThread extends Thread { + + + private InetSocketAddress addr; + private ServiceRegistrationMessage msg; + private Service srv; + + private UpdaterThread(InetSocketAddress sock, ServiceRegistrationMessage message,final Service service) { + addr=sock; + msg=message; + srv=service; + start(); + } + + /** + * thread's main loop. + */ + public void run() { + try{ + AbstractSLPReplyMessage rm = SLPCore.sendReliableUnicastMessage(msg, addr, true); + if (rm!=null){ + if (rm.getErrorCode()!=0){ + //DA may not udnerstand updates... + msg.setAttrList(SLPUtils.listToStringArray(SLPUtils.dictToAttrList(srv.getAttributes()))); + msg.setAuthBlocks(srv.getAuthBlocks()); + msg.setXid(SLPCore.nextXid()); + msg.setFresh(true); + if (SLPCore.CONFIG.getSecurityEnabled()) { + List spiList = SLPCore.dASPIs.get(addr); + msg.sign((String[]) spiList.toArray(new String[]{})); + } + rm = SLPCore.sendReliableUnicastMessage(msg, addr, true); + if (rm==null){ +// remove DA from list + SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress()); + SLPCore.dASPIs.remove( addr.getAddress().getHostAddress()); + } + } + } else { + + //remove DA from list + SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress()); + SLPCore.dASPIs.remove( addr.getAddress().getHostAddress()); + } + + SLPCore.platform.logTraceReg("ANNOUNCED " + + ((ServiceRegistrationMessage)msg).getServiceURL() + " to " + addr.getAddress().getHostAddress()); + + + } catch (ServiceLocationException sle){ + + // remove DA from list + SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress()); + SLPCore.dASPIs.remove( addr.getAddress().getHostAddress()); + SLPCore.platform.logError(sle.getMessage(), sle.fillInStackTrace()); + + } + } + } +} Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java?rev=782968&view=auto ============================================================================== --- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java (added) +++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java Tue Jun 9 12:00:29 2009 @@ -0,0 +1,432 @@ +/* + * 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.net.InetSocketAddress; + +import org.apache.directory.slp.ServiceLocationException; +import org.apache.directory.slp.messages.AbstractSLPMessage; +import org.apache.directory.slp.messages.AbstractSLPRequestMessage; +import org.apache.directory.slp.messages.AttributeReplyMessage; +import org.apache.directory.slp.messages.DAAdvertisementMessage; +import org.apache.directory.slp.messages.ServiceAcknowledgementMessage; +import org.apache.directory.slp.messages.ServiceRegistrationMessage; +import org.apache.directory.slp.messages.ServiceReplyMessage; +import org.apache.mina.core.service.IoHandlerAdapter; +import org.apache.mina.core.session.IdleStatus; +import org.apache.mina.core.session.IoSession; + + +/** + * The IoHandler processing incoming SLP messages and dispatching them to the correct agent for processing + * + * @author Lorenz Breu + * + */ +public class SLPHandler extends IoHandlerAdapter{ + + + public SLPHandler(){ + + } + + @Override + public void exceptionCaught(IoSession session, Throwable cause) + throws Exception { + cause.printStackTrace(); + session.close(false); + } + + @Override + public void messageReceived(IoSession session, Object message) throws ServiceLocationException { + + if (message == null || !(message instanceof AbstractSLPMessage)) { + return; + } + AbstractSLPMessage msg = (AbstractSLPMessage) message; + + + + InetSocketAddress address = (InetSocketAddress) session.getRemoteAddress(); + SLPCore.platform.logDebug("RECEIVED (" + msg.getSource() + ":" + + msg.getPort() + ") " + msg.toString()); + + switch (msg.getFuncID()) { + case AbstractSLPMessage.DAADVERT: + // drop message, if noDADiscovery is set + if (SLPCore.noDiscovery) { + if (SLPCore.discoveryException.equals(address.getAddress().getHostAddress())){ + SLPCore.addReply(msg, address); + } else { + SLPCore.platform.logTraceDrop("DROPPED (" + address.getAddress() + ":" + + address.getPort() + ") " + msg.toString() + + "(reason: noDADiscovery is set"); + } + session.close(false); + return; + } + + DAAdvertisementMessage advert = (DAAdvertisementMessage) message; + + if (advert.getErrorCode() != 0) { + SLPCore.platform.logTraceDrop("DROPPED DAADvertisement (" + address.getAddress() + ":" + + address.getPort() + ") " + advert.toString() + + "(reason: " + advert.getErrorCode() + " != 0"); + session.close(false); + return; + } + // this should also prevent reverse-lookup each time a DA is contacted + if (advert.getServiceURL().getHost() != address.getAddress().getHostAddress()) { + advert.getServiceURL().setHost(address.getAddress().getHostAddress()); + } + + // statelessBootTimestamp = 0 means DA is going down + if (advert.getStatelessBootTimestamp() == 0) { + for (int i=0;iSLPCore.CONFIG.getMTU()){ + SLPCore.sendMessageTCP(reply, new InetSocketAddress(msg.getSource(),SLPCore.SLP_PORT), false); + session.close(false); + return; + } + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + session.close(false); + return; + } + + + // else if we have a daemon instance, delegate the + // message to the daemon. + if (SLPCore.getDaemon() != null) { + AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg); + if (reply!=null){ + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + if (reply.getSize()>SLPCore.CONFIG.getMTU()){ + SLPCore.sendMessageTCP(reply, new InetSocketAddress(msg.getSource(),SLPCore.SLP_PORT), false); + session.close(false); + return; + } + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + + session.close(false); + return; + } else { + SLPCore.platform.logDebug("Request recieved (" + + address.getAddress().getHostAddress() + ":" + address.getPort() + ") " + + msg.toString() + + " but no SLPDaemon to handle the message present"); + session.close(false); + return; + } + + case AbstractSLPMessage.SRVREG: + + if (SLPCore.CONFIG.getSecurityEnabled()){ + if (!((ServiceRegistrationMessage)msg).verify()){ + ServiceAcknowledgementMessage ack = new ServiceAcknowledgementMessage(); + ack.setXid(msg.getXid()); + ack.setErrorCode(ServiceLocationException.AUTHENTICATION_FAILED); + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(ack, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + session.write(ack); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + ack + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + } + + // if the reg comes from within the framework, pass it to the SA part... + if (SLPUtils.arrayToList(SLPCore.myIPs).contains(msg.getSource())){ + if (SLPCore.getDaemon()!=null){ + AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg); + if (reply!=null){ + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + session.close(false); + return; + } + } + // this reg comes from outside + if (SLPCore.getDirectoryAgentDaemon() != null) { + AbstractSLPMessage reply = SLPCore.getDirectoryAgentDaemon().handleMessage(msg); + if (reply!=null){ + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + session.close(false); + return; + } + + case AbstractSLPMessage.SRVDEREG: + // if the reg comes from within the framework, pass it to the SA part... + if (SLPUtils.arrayToList(SLPCore.myIPs).contains(msg.getSource())){ + if (SLPCore.getDaemon()!=null){ + AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg); + if (reply!=null){ + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + session.close(false); + return; + } + } + // this reg comes from outside + if (SLPCore.getDirectoryAgentDaemon() != null) { + AbstractSLPMessage reply = SLPCore.getDirectoryAgentDaemon().handleMessage(msg); + if (reply!=null){ + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + session.close(false); + return; + } + + case AbstractSLPMessage.SRVACK: + if (msg.hasUnsupportedMandatoryExtensions()){ + return; + } + + SLPCore.addReply(msg, new InetSocketAddress(msg.getSource(),msg.getPort())); + return; + + + default: + // if we have a DA running, pass messages (in this case reg and dereg) to it. + // the da will relegate reg and deregs coming from the framework on to the SA if present + if (SLPCore.getDirectoryAgentDaemon() != null) { + AbstractSLPMessage reply = SLPCore.getDirectoryAgentDaemon().handleMessage(msg); + if (reply!=null){ + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + session.close(false); + return; + } + + + // if we have a daemon instance but no DA, delegate all other + // messages to the daemon. + if (SLPCore.getDaemon() != null) { + AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg); + if (reply!=null){ + if (msg.isMulticast()){ + SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false); + } else { + session.write(reply); + SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") " + + reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort() + + ")"); + } + } + + session.close(false); + return; + } else { + SLPCore.platform.logDebug("A message recieved (" + + address.getAddress() + ":" + address.getPort() + ") " + + msg.toString() + + " but no SLPDaemon to handle the message present"); + session.close(false); + return; + } + } + +} + + @Override + public void sessionClosed(IoSession session) throws Exception { + + } + + @Override + public void sessionCreated(IoSession session) throws Exception { + + + } + + @Override + public void sessionIdle(IoSession session, IdleStatus status) + throws Exception { + + } + + @Override + public void sessionOpened(IoSession session) throws Exception { + + } +} + + + Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java?rev=782968&view=auto ============================================================================== --- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java (added) +++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java Tue Jun 9 12:00:29 2009 @@ -0,0 +1,567 @@ +/* + * 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.Dictionary; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +import org.apache.directory.slp.OpaqueValue; + + +/** + * Utility class. + * + * @author Jan S. Rellermeyer + */ +public final class SLPUtils { + + public static final String KEYWORD_STRING = "jslpkeyword"; + + + /** + * hidden constructor. + */ + private SLPUtils() { + + } + + /** + * get a List of attribute/value pairs in String + * representation from a Dictionary. + * + * @param attributes + * the Dictionary + * @return the List. + */ + public static List dictToAttrList(final Dictionary attributes) { + List attList = new ArrayList(); + if (attributes != null) { + for (Enumeration keys = attributes.keys(); keys.hasMoreElements();) { + Object key = keys.nextElement(); + if (attributes.get(key).equals(KEYWORD_STRING)){ + attList.add(key.toString()); + continue; + } + StringBuffer buffer = new StringBuffer(); + buffer.append("("); + buffer.append(key); + buffer.append("="); + buffer.append(attributes.get(key)); + buffer.append(")"); + attList.add(buffer.toString()); + } + } + return attList; + } + + + public static String dictToString(final Dictionary attributes){ + return listToString(dictToAttrList(attributes), ","); + } + + /** + * get a Dictionary of attributes and their values from an + * attribute List. + * + * @since 0.6 + * @param attrList + * the attribute list. + * @return the Dictionary. + */ + static Dictionary attrListToDict(final List attrList) { + Dictionary dict = new Hashtable(); + + for (Iterator iter = attrList.iterator(); iter.hasNext();) { + String attrStr = (String) iter.next(); + attrStr = attrStr.substring(1, attrStr.length() - 1); + int pos = attrStr.indexOf("="); + if (pos > -1) { + String key = attrStr.substring(0, pos).trim(); + String value = attrStr.substring(pos + 1).trim(); + dict.put(key, value); + } + } + + return dict; + } + + /** + * This is the most important method of the class. It is used to parse the + * attribute lists from their string form as received in messages to their typed + * form in the Service object. + * + * @param arr + * The attributes as an array of string representations + * @return + */ + public static Dictionary stringArrayToDict(final String[] arr){ + Dictionary dict = new Hashtable(); + for (int i=0;i-1){ + String key = attrStr.substring(0, pos).trim(); + String value = attrStr.substring(pos+1).trim(); + //added by Lorenz to support multivalued attributes + String valueRep = value.replace("\\,", "SLP_ESCAPED_COMMA"); + String[] valuesRep = valueRep.split(","); + String[] valuesFixed = new String[valuesRep.length]; + int k = 0; + for (String s: valuesRep){ + valuesFixed[k++] = s.replace("SLP_ESCAPED_COMMA", "\\,").trim(); + } + + if (valuesFixed.length==1){ + if (value.toLowerCase().equals("true") || value.toLowerCase().equals("false")) { + dict.put(key, new Boolean(value) ); + } else if (value.startsWith("\\FF")) { + dict.put(key, new OpaqueValue(value) ); + } else { + try { + int v = Integer.parseInt(value); + dict.put(key, v); + } catch (NumberFormatException e){ + dict.put(key, value); + } + } + + continue; + } + + Object[] values; + String type; + String value1 = valuesFixed[0]; + if (value1.startsWith("\\FF")){ + values = new OpaqueValue[valuesFixed.length]; + values[0]=new OpaqueValue(value1); + type="opaque"; + } else if (value1.toLowerCase().equals("true") || value1.toLowerCase().equals("false")){ + values = new Boolean[valuesFixed.length]; + values[0]= Boolean.valueOf(value1); + type="boolean"; + } else { + try { + int v = Integer.parseInt(value1); + values = new Number[valuesFixed.length]; + values[0] = v; + type="integer"; + } catch (NumberFormatException e){ + values = new String[valuesFixed.length]; + values[0]=value1; + type="string"; + } + } + for (int j=1;j stringToList(final String str, final String delim) { + List result = new ArrayList(); + String strFixed = str.replace("\\"+delim, "SLP_ESCAPED_DELIM"); + StringTokenizer tokenizer = new StringTokenizer(strFixed, delim); + while (tokenizer.hasMoreTokens()) { + result.add(tokenizer.nextToken().replace("SLP_ESCAPED_DELIM", "\\"+delim)); + } + return result; + } + + public static List arrayToList(final String[] arr){ + List result = new ArrayList(); + for (int i=0;i< arr.length;i++){ + result.add(arr[i]); + } + + return result; + } + + public static String[] listToStringArray(final List list){ + if (list==null){ + return new String[]{}; + } + if (list.isEmpty()){ + return new String[]{}; + } + String[] result = new String[list.size()]; + for (int i = 0;i result = new ArrayList(); + String strFixed = string.replace("\\"+delim, "SLP_ESCAPED_DELIM"); + StringTokenizer tokenizer = new StringTokenizer(strFixed, delim); + while (tokenizer.hasMoreTokens()) { + result.add(tokenizer.nextToken().replace("SLP_ESCAPED_DELIM","\\"+delim)); + } + return result.toArray(new String[]{}); + } + + + + + /** + * add a value to a value list in a Map. + * + * @param map + * the map. + * @param key + * the key. + * @param value + * the value to be added to the list. + */ + static void addValue(final Map map, final Object key, final Object value) { + + List values; + if ((values = (List) map.get(key)) == null) { + values = new ArrayList(); + } + if (values.contains(value)) { + return; + } + values.add(value); + map.put(key, values); + } + + /** + * remove a value from a value list in a Map. + * + * @param map + * the map. + * @param key + * the key. + * @param value + * the value to be removed from the list. + */ + static void removeValue(final Map map, final Object key, final Object value) { + List values; + if ((values = (List) map.get(key)) == null) { + return; + } + values.remove(value); + if (!values.isEmpty()) { + map.put(key, values); + } else { + map.remove(key); + } + } + + /** + * remove a value from all keys where it occurs. + * + * @param map + * the map. + * @param value + * the value. + */ + static void removeValueFromAll(final Map map, final Object value) { + final Object[] keys = map.keySet().toArray(); + for (int i = 0; i < keys.length; i++) { + List list = (List) map.get(keys[i]); + list.remove(value); + if (list.isEmpty()) { + map.remove(keys[i]); + } + } + } + + /** + * get the current timestamp as defined in RFC 2608. + * + * @return the current timestamp. + */ + public static int getTimestamp() { + long systemTime = System.currentTimeMillis(); + systemTime /= 1000; + return (int) systemTime; + } + + /** + * find case insensitive matching between a key List and a Dictionary of + * attributes. + * + * @param keyList + * the key List. + * @param attributes + * the attribute Dictionary. + * @return a List of matches. + */ + public static List findMatches(final List keyList, final Dictionary attributes) { + List results = new ArrayList(); + Set caseInsensitiveKeyList = new HashSet(); + List wildcards = new ArrayList(); + if (!keyList.isEmpty()) { + for (Iterator keys = keyList.iterator(); keys.hasNext();) { + String key = (String) keys.next(); + if (key.indexOf("*") == -1) { + caseInsensitiveKeyList.add(key.toLowerCase()); + } else { + wildcards.add(key); + } + } + } + + for (Enumeration keys = attributes.keys(); keys.hasMoreElements();) { + String key = (String) keys.nextElement(); + if (keyList.isEmpty() + || caseInsensitiveKeyList.contains(key.toLowerCase())) { + results.add("(" + key + "=" + attributes.get(key).toString() + + ")"); + continue; + } + for (Iterator iter = wildcards.iterator(); iter.hasNext();) { + String wildcard = (String) iter.next(); + if (equalsWithWildcard(wildcard.toCharArray(), 0, key + .toCharArray(), 0)) { + results.add("(" + key + "=" + + attributes.get(key).toString() + ")"); + continue; + } + } + + } + return results; + } + + /** + * equality check with wildcards + * + * @param val + * the value + * @param valIndex + * the current position within the value + * @param attr + * the attribute + * @param attrIndex + * the current position within the attribute. + * @return true if equals. + */ + private static boolean equalsWithWildcard(char[] val, int valIndex, + char[] attr, int attrIndex) { + if (val.length == valIndex) { + return attr.length == attrIndex; + } + if (val[valIndex] == '*') { + valIndex++; + do { + if (equalsWithWildcard(val, valIndex, attr, attrIndex)) { + return true; + } + attrIndex++; + } while (attr.length - attrIndex > -1); + return false; + } else { + return (attr.length == attrIndex || attr[attrIndex] != val[valIndex]) ? false + : equalsWithWildcard(val, ++valIndex, attr, ++attrIndex); + } + } + + + /** + * Merges the SLP attribute-list by merging multiple attributes with the same name and type into one + * + * @param atts + * The atttribute list as a a list of SLP atribute strings (name=value) + * @return + * The merged attributes as an array + */ + public static String[] mergeAttributes(List atts){ + Map> ad = new Hashtable>(); + List keywords = new ArrayList(); + + for (String s : atts){ + String[] fields = s.split("="); + String at_name = fields[0]; + if (at_name.startsWith("(")){ + at_name=at_name.substring(1); + } + if (at_name.endsWith(")")){ + at_name=at_name.substring(0, at_name.length()-1); + } + if (fields.length==1 && !keywords.contains(at_name)){ + keywords.add(at_name); + continue; + } + if (ad.keySet().contains(at_name)){ + for (String s2:stringToList(fields[1].substring(0, fields[1].length()-1), ",")){ + List current = ad.get(at_name); + if (!current.contains(s2)){ + current.add(s2); + } + } + continue; + } + ad.put(at_name, stringToList(fields[1].substring(0, fields[1].length()-1), ",")); + } + + List result = new ArrayList(); + Set keys = ad.keySet(); + for (String k:keys){ + result.add("("+k+"="+listToString(ad.get(k), ",")+")"); + } + for (String kw:keywords){ + result.add(kw); + } + return listToStringArray(result); + + } + + /** + * Merges the SLP attribute-list by merging multiple attributes with the same name and type into one + * + * @param atts + * The atttribute list as a an array of SLP atribute strings (name=value) + * @return + * The merged attributes as an array + */ + public static String[] mergeAttributes(String[] atts){ + Map> ad = new Hashtable>(); + List keywords = new ArrayList(); + + for (String s : atts){ + String[] fields = s.split("="); + String at_name = fields[0]; + if (at_name.startsWith("(")){ + at_name=at_name.substring(1); + } + if (at_name.endsWith(")")){ + at_name=at_name.substring(0, at_name.length()-1); + } + if (fields.length==1 && !keywords.contains(at_name)){ + keywords.add(at_name); + continue; + } + if (ad.keySet().contains(at_name)){ + for (String s2:stringToList(fields[1].substring(0, fields[1].length()-1), ",")){ + List current = ad.get(at_name); + if (!current.contains(s2)){ + current.add(s2); + } + } + continue; + } + ad.put(at_name, stringToList(fields[1].substring(0, fields[1].length()-1), ",")); + } + + List result = new ArrayList(); + Set keys = ad.keySet(); + for (String k:keys){ + result.add("("+k+"="+listToString(ad.get(k), ",")+")"); + } + for (String kw:keywords){ + result.add(kw); + } + return listToStringArray(result); + + } + +} Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java?rev=782968&view=auto ============================================================================== --- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java (added) +++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java Tue Jun 9 12:00:29 2009 @@ -0,0 +1,97 @@ +/* + * 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.Iterator; +import java.util.List; + +import org.apache.directory.slp.ServiceLocationEnumeration; +import org.apache.directory.slp.ServiceLocationException; + + +/** + * the implementation of a ServiceLocationEnumeration. + * + * @see org.apache.directory.slp.ServiceLocationEnumeration + * @author Jan S. Rellermeyer + */ +class ServiceLocationEnumerationImpl implements ServiceLocationEnumeration { + /** + * a list of results. + */ + private List list; + + /** + * internal Iterator over the elements of the list. + */ + private Iterator iterator; + + /** + * creates a new ServiceLocationEnumerationImpl. + * + * @param resultList + * a list of results. + */ + ServiceLocationEnumerationImpl(final List resultList) { + list = resultList != null ? resultList : new ArrayList(); + this.iterator = list.iterator(); + } + + /** + * returns the next element of the Enumeration. + * + * @return the next element. + * @throws ServiceLocationException + * if there is no more element. + * @see org.apache.directory.slp.ServiceLocationEnumeration#next() + */ + public synchronized Object next() throws ServiceLocationException { + try { + return iterator.next(); + } catch (Exception e) { + throw new ServiceLocationException( + ServiceLocationException.INTERNAL_SYSTEM_ERROR, e + .getMessage()); + } + } + + /** + * checks if the Enumeration has more elements. + * + * @return true if there are more elements available. + */ + public synchronized boolean hasMoreElements() { + return iterator.hasNext(); + } + + /** + * returns the next elenemt of the Enumeration. + * + * @return the next element or null if there aren't any more. + */ + public synchronized Object nextElement() { + try { + return next(); + } catch (ServiceLocationException sle) { + return null; + } + } +} Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java?rev=782968&view=auto ============================================================================== --- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java (added) +++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java Tue Jun 9 12:00:29 2009 @@ -0,0 +1,208 @@ +/* + * 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.Service; +import org.apache.directory.slp.ServiceLocationException; +import org.apache.directory.slp.ServiceReplyFuture; +import org.apache.directory.slp.ServiceURL; +import org.apache.directory.slp.extensions.AbstractExtension; +import org.apache.directory.slp.extensions.AttributeListExtension; +import org.apache.directory.slp.extensions.UnsupportedExtension; +import org.apache.directory.slp.messages.AbstractSLPReplyMessage; +import org.apache.directory.slp.messages.ServiceReplyMessage; + +/** + * + * @author Lorenz Breu + */ +public class ServiceReplyFutureImpl extends NonThreadedReplyFuture implements + ServiceReplyFuture { + + // List of responses (i.e. message results) + private final List services = new ArrayList(); + + // next service to return when next() is called + private int nextServicePosition = 0; + + /** + * Creates a new ServiceReplyFuture with a timeout of 5x the WaitTime in + * SLPConfiguration + */ + public ServiceReplyFutureImpl() { + super(SLPCore.CONFIG.getWaitTime() * 5); + } + + /** + * Creates a new ServiceReplyFuture with the specified lifetime (in ms) + * + * @param lifetime + * The time until the ReplyFuture is considered done in ms + */ + public ServiceReplyFutureImpl(long lifetime) { + super(lifetime); + } + + /** + * Creates a new AttributeReplyFuture with the specified lifetime (in ms) + * expecting responses for the specified scopes. + * + * @param lifetime + * The lifetime in ms + * @param scopes + * The scopes for which replies are expected. used for completion + * checks + */ + public ServiceReplyFutureImpl(long lifetime, List scopes) { + super(lifetime, scopes); + } + + @Override + public void add(AbstractSLPReplyMessage reply) { + + if (reply == null || reply.getErrorCode() != 0) { + return; + } + if (done) { + // this reply is coming in too late... + return; + } + + synchronized (responders) { + if (!responders.contains(reply.getSource())) { + responders.add(reply.getSource()); + } else { + return; + } + } + + if (reply instanceof ServiceReplyMessage) { + for (String s : reply.getResult()) { + try { + Service srv = new Service(new ServiceURL(s, 0)); + synchronized (services) { + services.add(srv); + } + + } catch (ServiceLocationException sle) { + continue; + } + } + processExtensions(reply); + + } + + // stick to the basic behaviour... + synchronized (responses) { + List res = reply.getResultAsList(); + if (res != null && res.size() > 0) { + List resp = reply.getResultAsList(); + for (String s : resp) { + if (!responses.contains(s)) { + responses.add(s); + } + } + responses.notifyAll(); + } + } + + } + + /** + * Process the extensions + * + * @param reply + * The reply message possibly containing extensions + * + */ + private void processExtensions(AbstractSLPReplyMessage reply) { + for (AbstractExtension ae : reply.getExtensions()) { + if (ae instanceof UnsupportedExtension) { + return; + } + switch (ae.getId()) { + case AbstractExtension.ATTRIBUTE_LIST_EXTENSION: + AttributeListExtension ale = (AttributeListExtension) ae; + if (SLPCore.CONFIG.getSecurityEnabled()) { + if (!ale.verify()) { + return; + } + } + synchronized (services) { + for (Service srv : services) { + if (srv.toString().toLowerCase().equals( + ale.getUrl().toLowerCase())) { + srv.setAttributes(SLPUtils + .stringArrayToDict(SLPUtils + .stringToStringArray(ale + .getAttributeList(), ","))); + } + } + } + + } + } + } + + public Service nextService() { + // NOTE: a future is currently only read by one consumer (i.e. + // LocatorImpl) and therefor a single + // position marker is sufficient. Also the data containers holding + // responses must add new elements to the end. + synchronized (services) { + while (!done) { + if (services.size() > nextServicePosition) { + return services.get(nextServicePosition++); + } + try { + services.wait(timeout - System.currentTimeMillis() + 1000); + } catch (InterruptedException e) { + + } + } + if (services.size() > nextServicePosition) { + return services.get(nextServicePosition++); + } + return null; + } + } + + /* + * (non-Javadoc) + * + * @see ch.ethz.iks.slp.ServiceReplyFuture#getResultServices() + */ + public List getResultServices() { + while (!done) { + synchronized (donelock) { + try { + donelock.wait(); + } catch (InterruptedException ie) { + + } + } + } + return services; + } + +} Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java ------------------------------------------------------------------------------ svn:mime-type = text/plain