From: Thomas Kee Date: Sun, 31 Aug 2014 19:58:29 +0000 (-0700) Subject: Add packetcable-driver as a bundle and fix karafe depends. Merge hop-along model... X-Git-Tag: release/helium-sr1~23 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F55%2F10555%2F1;p=packetcable.git Add packetcable-driver as a bundle and fix karafe depends. Merge hop-along model rewrites. Ensure build sanity. Change-Id: I83e7fd93fdc7650250a3e05c4903217417b4812d Signed-off-by: Thomas Kee --- diff --git a/features-packetcable/pom.xml b/features-packetcable/pom.xml index 2a3c3dd..0e9e421 100644 --- a/features-packetcable/pom.xml +++ b/features-packetcable/pom.xml @@ -60,13 +60,6 @@ features xml - - org.opendaylight.openflowplugin - features-openflowplugin - 0.0.3-SNAPSHOT - features - xml - org.opendaylight.controller features-flow @@ -99,9 +92,14 @@ packetcable-model ${project.version} + + org.opendaylight.controller.packetcable + packetcable-driver + ${project.version} + odl-yangtools-binding odl-yangtools-models - -odl-flow-model + odl-flow-model mvn:org.opendaylight.controller.packetcable/packetcable-model/${project.version} @@ -56,9 +56,15 @@ odl-mdsal-broker mvn:org.opendaylight.controller.packetcable/packetcable-provider/${project.version} - -odl-flow-model + mvn:org.opendaylight.controller.packetcable/packetcable-driver/${project.version} + odl-flow-model odl-packetcable-model + odl-packetcable-driver + + + odl-mdsal-broker + + diff --git a/packetcable-consumer/pom.xml b/packetcable-consumer/pom.xml index c1da112..1f76dc3 100644 --- a/packetcable-consumer/pom.xml +++ b/packetcable-consumer/pom.xml @@ -20,6 +20,11 @@ ${project.version} + ${project.groupId} + packetcable-driver + ${project.version} + + org.opendaylight.controller config-api diff --git a/packetcable-consumer/src/main/java/org/opendaylight/controller/config/yang/config/pcmm_service/impl/PcmmServiceModule.java b/packetcable-consumer/src/main/java/org/opendaylight/controller/config/yang/config/pcmm_service/impl/PcmmServiceModule.java new file mode 100644 index 0000000..7c20cf5 --- /dev/null +++ b/packetcable-consumer/src/main/java/org/opendaylight/controller/config/yang/config/pcmm_service/impl/PcmmServiceModule.java @@ -0,0 +1,52 @@ +package org.opendaylight.controller.config.yang.config.pcmm_service.impl; + +import org.opendaylight.controller.org.pcmm.api.PcmmService; +import org.opendaylight.controller.org.pcmm.impl.PcmmServiceImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.service.rev140120.PacketcableServiceService; +import org.opendaylight.yangtools.concepts.Registration; + +public class PcmmServiceModule + extends + org.opendaylight.controller.config.yang.config.pcmm_service.impl.AbstractPcmmServiceModule { + public PcmmServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public PcmmServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.pcmm_service.impl.PcmmServiceModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + // add custom validation form module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + PacketcableServiceService packetcableServiceService = getRpcRegistryDependency().getRpcService(PacketcableServiceService.class); + final PcmmService pcmmService = new PcmmServiceImpl(packetcableServiceService); + final Registration pcmmListenerReg = getNotificationServiceDependency().registerNotificationListener(pcmmService); + final PcmmServiceRuntimeRegistration runtimeReg = getRootRuntimeBeanRegistratorWrapper().register(pcmmService); + return new AutoCloseablePcmmService(packetcableServiceService, pcmmListenerReg, runtimeReg); + } + + class AutoCloseablePcmmService extends PcmmServiceImpl implements + AutoCloseable { + + private PcmmServiceRuntimeRegistration runtimeReg; + private Registration pcmmListenerReg; + + public AutoCloseablePcmmService(PacketcableServiceService packetcableServiceService, Registration pcmmListenerReg, PcmmServiceRuntimeRegistration runtimeReg) { + super(packetcableServiceService); + this.runtimeReg = runtimeReg; + this.pcmmListenerReg = pcmmListenerReg; + } + + @Override + public void close() throws Exception { + pcmmListenerReg.close(); + runtimeReg.close(); + } + + } +} diff --git a/packetcable-consumer/src/main/java/org/opendaylight/controller/config/yang/config/pcmm_service/impl/PcmmServiceModuleFactory.java b/packetcable-consumer/src/main/java/org/opendaylight/controller/config/yang/config/pcmm_service/impl/PcmmServiceModuleFactory.java new file mode 100644 index 0000000..7c6662c --- /dev/null +++ b/packetcable-consumer/src/main/java/org/opendaylight/controller/config/yang/config/pcmm_service/impl/PcmmServiceModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: pcmm-service-impl yang module local name: pcmm-service-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Mon Aug 11 19:34:09 CEST 2014 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.config.pcmm_service.impl; +public class PcmmServiceModuleFactory extends org.opendaylight.controller.config.yang.config.pcmm_service.impl.AbstractPcmmServiceModuleFactory { + +} diff --git a/packetcable-consumer/src/main/java/org/opendaylight/controller/org/pcmm/api/PcmmService.java b/packetcable-consumer/src/main/java/org/opendaylight/controller/org/pcmm/api/PcmmService.java new file mode 100644 index 0000000..c5d5317 --- /dev/null +++ b/packetcable-consumer/src/main/java/org/opendaylight/controller/org/pcmm/api/PcmmService.java @@ -0,0 +1,9 @@ +package org.opendaylight.controller.org.pcmm.api; + +import org.opendaylight.controller.config.yang.config.pcmm_service.impl.PcmmServiceRuntimeMXBean; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.service.rev140120.PacketcableServiceListener; + +public interface PcmmService extends PcmmServiceRuntimeMXBean, + PacketcableServiceListener { + +} diff --git a/packetcable-consumer/src/main/java/org/opendaylight/controller/org/pcmm/impl/PcmmServiceImpl.java b/packetcable-consumer/src/main/java/org/opendaylight/controller/org/pcmm/impl/PcmmServiceImpl.java new file mode 100644 index 0000000..8972271 --- /dev/null +++ b/packetcable-consumer/src/main/java/org/opendaylight/controller/org/pcmm/impl/PcmmServiceImpl.java @@ -0,0 +1,99 @@ +package org.opendaylight.controller.org.pcmm.impl; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +import org.opendaylight.controller.org.pcmm.api.PcmmService; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.rev140120.CmtsReference; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.service.rev140120.CmtsAdded; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.service.rev140120.CmtsRemoved; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.service.rev140120.CmtsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.service.rev140120.PacketcableServiceService; +import org.pcmm.rcd.IPCMMPolicyServer; +import org.pcmm.rcd.IPCMMPolicyServer.IPSCMTSClient; +import org.pcmm.rcd.impl.PCMMPolicyServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +public class PcmmServiceImpl implements PcmmService { + + private static final Logger log = LoggerFactory.getLogger(PcmmServiceImpl.class); + private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); + private PacketcableServiceService packetcableServiceService; + private List cmtsList; + private Map cmtsClients; + private IPCMMPolicyServer policyServer; + + public PcmmServiceImpl(PacketcableServiceService packetcableServiceService) { + this.packetcableServiceService = packetcableServiceService; + policyServer = new PCMMPolicyServer(); + cmtsClients = Maps.newConcurrentMap(); + cmtsList = Lists.newArrayList(); + } + + @Override + public void onCmtsAdded(CmtsAdded notification) { + String ipv4 = notification.getId().getIpv4Address().getValue(); + IPSCMTSClient client = policyServer.requestCMTSConnection(ipv4); + if (client.isConnected()) { + cmtsClients.put(notification.getCmtsRef(), client); + cmtsList.add(notification.getId()); + } + } + + @Override + public void onCmtsRemoved(CmtsRemoved notification) { + if (cmtsList.contains(notification.getId())) + cmtsList.remove(notification.getId()); + if (cmtsClients.containsKey(notification.getCmtsRef())) { + IPSCMTSClient client = cmtsClients.remove(notification.getCmtsRef()); + client.disconnect(); + } + } + + @Override + public void onCmtsUpdated(CmtsUpdated notification) { + // TODO + } + + @Override + public Boolean sendGateDelete() { + // TODO change me + boolean ret = true; + for (Iterator iter = cmtsClients.values().iterator(); iter.hasNext();) + ret &= cmtsClients.get(0).gateDelete(); + return ret; + } + + @Override + public Boolean sendGateSynchronize() { + boolean ret = true; + for (Iterator iter = cmtsClients.values().iterator(); iter.hasNext();) + ret &= cmtsClients.get(0).gateSynchronize(); + return ret; + } + + @Override + public Boolean sendGateInfo() { + boolean ret = true; + for (Iterator iter = cmtsClients.values().iterator(); iter.hasNext();) + ret &= cmtsClients.get(0).gateInfo(); + return ret; + } + + @Override + public Boolean sendGateSet() { + boolean ret = true; + for (Iterator iter = cmtsClients.values().iterator(); iter.hasNext();) + ret &= cmtsClients.get(0).gateSet(); + return ret; + } +} diff --git a/packetcable-consumer/src/main/yang/pcmm-service-impl.yang b/packetcable-consumer/src/main/yang/pcmm-service-impl.yang new file mode 100644 index 0000000..8b7e78d --- /dev/null +++ b/packetcable-consumer/src/main/yang/pcmm-service-impl.yang @@ -0,0 +1,153 @@ +module pcmm-service-impl { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:pcmm-service:impl"; + prefix "pcmm-service-impl"; + + import config { prefix config; revision-date 2013-04-05; } + import rpc-context { prefix rpcx; revision-date 2013-06-17; } + + import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } + + description + "This module contains the base YANG definitions for + pcmm-service impl implementation."; + + revision "2014-08-10" { + description + "Initial revision."; + } + + // This is the definition of pcmm service interface identity. + identity pcmm-service { + base "config:service-type"; + config:java-class "org.opendaylight.controller.org.pcmm.api.PcmmService"; + } + + // This is the definition of pcmm service implementation module identity. + identity pcmm-service-impl { + base config:module-type; + config:provided-service pcmm-service; + config:java-name-prefix PcmmService; + } + + augment "/config:modules/config:module/config:configuration" { + case pcmm-service-impl { + when "/config:modules/config:module/config:type = 'pcmm-service-impl'"; + + container rpc-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-rpc-registry; + } + } + } + + container notification-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-notification-service; + } + } + } + } + } + + augment "/config:modules/config:module/config:state" { + case pcmm-service-impl { + when "/config:modules/config:module/config:type = 'pcmm-service-impl'"; + + rpcx:rpc-context-instance "send-gate-set-rpc"; + rpcx:rpc-context-instance "send-gate-delete-rpc"; + rpcx:rpc-context-instance "send-gate-info-rpc"; + rpcx:rpc-context-instance "send-gate-synchronize-rpc"; + + } + } + + identity send-gate-set-rpc; + + rpc send-gate-set { + description + "Shortcut JMX call to send a gate-set message for testing."; + + input { + uses rpcx:rpc-context-ref { + refine context-instance { + rpcx:rpc-context-instance send-gate-set-rpc; + } + } + } + + output { + leaf result { + type boolean; + } + } + } + + identity send-gate-delete-rpc; + + rpc send-gate-delete { + description + "Shortcut JMX call to send a gate-delete message for testing."; + + input { + uses rpcx:rpc-context-ref { + refine context-instance { + rpcx:rpc-context-instance send-gate-delete-rpc; + } + } + } + + output { + leaf result { + type boolean; + } + } + } + + identity send-gate-synchronize-rpc; + + rpc send-gate-synchronize { + description + "Shortcut JMX call to send a gate-Synchronize message for testing."; + + input { + uses rpcx:rpc-context-ref { + refine context-instance { + rpcx:rpc-context-instance send-gate-synchronize-rpc; + } + } + } + + output { + leaf result { + type boolean; + } + } + } + + identity send-gate-info-rpc; + + rpc send-gate-info { + description + "Shortcut JMX call to send a gate-info message for testing."; + + input { + uses rpcx:rpc-context-ref { + refine context-instance { + rpcx:rpc-context-instance send-gate-info-rpc; + } + } + } + + output { + leaf result { + type boolean; + } + } + } +} \ No newline at end of file diff --git a/packetcable-driver/.gitignore b/packetcable-driver/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/packetcable-driver/.gitignore @@ -0,0 +1 @@ +/target diff --git a/packetcable-driver/Makefile b/packetcable-driver/Makefile new file mode 100644 index 0000000..f7a5699 --- /dev/null +++ b/packetcable-driver/Makefile @@ -0,0 +1,82 @@ +# define compiler and compiler flag variables + +JFLAGS = -g +JC = javac +JUNIT=/usr/share/junit/junit.jar +JCOPS=src/main/java/jcops.jar +PCMM=src/main/java/pcmm.jar +CLASSPATH = -classpath .:$(PCMM):$(JCOPS):$(JUNIT) +JFLAGS = -encoding UTF-8 $(CLASSPATH) +JAR_PKG = Test.jar + + +# +# Clear any default targets for building .class files from .java files; we +# will provide our own target entry to do this in this makefile. +# make has a set of default targets for different suffixes (like .c.o) +# Currently, clearing the default for .java.class is not necessary since +# make does not have a definition for this target, but later versions of +# make may, so it doesn't hurt to make sure that we clear any default +# definitions for these +# + +.SUFFIXES: .java .class + + +# +# Here is our target entry for creating .class files from .java files +# This is a target entry that uses the suffix rule syntax: +# DSTS: +# rule +# 'TS' is the suffix of the target file, 'DS' is the suffix of the dependency +# file, and 'rule' is the rule for building a target +# '$*' is a built-in macro that gets the basename of the current target +# Remember that there must be a < tab > before the command line ('rule') +# + +.java.class: + $(JC) $(JFLAGS) $*.java + + +# +# CLASSES is a macro consisting of 4 words (one for each java source file) +# + +SOURCES = \ + Main.java \ + Test.java + + +CLASSES = $(SOURCES:%.java=%.class) + +# +# the default make target entry +# + +default: classes + + +# +# This target entry uses Suffix Replacement within a macro: +# $(name:string1=string2) +# In the words in the macro named 'name' replace 'string1' with 'string2' +# Below we are replacing the suffix .java of all words in the macro CLASSES +# with the .class suffix +# + +classes: $(SOURCES:.java=.class) + +jar: + jar cve $(JAR_PKG) $(CLASSES) + +tar: + tar czpf $(TARBALL) $(SOURCES) Makefile + + +# +# RM is a predefined macro in make (RM = rm -f) +# + +clean: + $(RM) *.class + diff --git a/packetcable-driver/pom.xml b/packetcable-driver/pom.xml new file mode 100644 index 0000000..00b09e4 --- /dev/null +++ b/packetcable-driver/pom.xml @@ -0,0 +1,124 @@ + + + 4.0.0 + + + org.opendaylight.controller.packetcable + packetcable-plugin + 1.1-SNAPSHOT + + packetcable-driver + bundle + + + A lightweight implementation of PCMM COPS PDP client + + + + 2013 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UTF-8 + 0.6.2-SNAPSHOT + src/main/yang-gen-sal + http://nexus.opendaylight.org/content + opendaylight.snapshot + opendaylight.release + + + + + junit + junit + 4.11 + + + ch.qos.logback + logback-core + 1.0.9 + + + ch.qos.logback + logback-classic + 1.0.9 + + + com.google.guava + guava + 13.0.1 + + + javax.sip + jain-sip-ri + 1.2.158 + + + commons-primitives + commons-primitives + 20041207.202534 + + + + + + + ${project.basedir}/target + ${project.build.directory}/classes + ${project.artifactId}-${project.version} + ${project.build.directory}/test-classes + ${project.basedir}/src/main/java + ${project.basedir}/src/test/java + + + ${project.basedir}/src/main/resources + + + + + ${project.basedir}/src/test/resources + + + + + maven-compiler-plugin + 3.0 + + 1.7 + 1.7 + + + + + diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMConstants.java b/packetcable-driver/src/main/java/org/pcmm/PCMMConstants.java new file mode 100644 index 0000000..accce63 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMConstants.java @@ -0,0 +1,19 @@ +package org.pcmm; + +public interface PCMMConstants { + + // Port used by the PCMM + public static final String PCMM_PORT = "pcmm.port"; + // Pool size, determining the number of connections that could be + // established with CMTSs + public static final String PS_POOL_SIZE = "pcmm.ps.pool.size"; + // Default keep-alive timer value (secs) + public static final String KA_TIMER = "pcmm.keep.alive.timer"; + // Default accounting timer value (secs) + public static final String ACC_TIMER = "pcmm.accounting.timer"; + // default ip mask + public static final String DEFAULT_MASK = "pcmm.default.mask"; + // default timeout + public static final String DEFAULT_TIEMOUT = "pcmm.default.timeout"; + +} \ No newline at end of file diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMDef.java b/packetcable-driver/src/main/java/org/pcmm/PCMMDef.java new file mode 100644 index 0000000..3b5758e --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMDef.java @@ -0,0 +1,30 @@ +/** + @header@ + */ + +package org.pcmm; + +import org.umu.cops.common.COPS_def; + +public class PCMMDef extends COPS_def { + + public static final short C_PCMM = (short) 0x800A; + + /** + * Get a representative string for an COPS Client Type. + * + * @param cType + * COPS Client Type + * @return A representative String + * + */ + public String strClientType(short cType) { + switch (cType) { + case C_PCMM: + return ("C_PCMM"); + default: + return super.strClientType(cType); + } + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMGlobalConfig.java b/packetcable-driver/src/main/java/org/pcmm/PCMMGlobalConfig.java new file mode 100644 index 0000000..4f7f605 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMGlobalConfig.java @@ -0,0 +1,88 @@ +/** + @header@ + */ + +package org.pcmm; + +public class PCMMGlobalConfig { + // System + public static int Debug = 0; + public static int LogLevel = 0; + public static int DefaultBestEffortTrafficRate = 2500000; + // Service Flow Attributes Defaults + public static int DefaultBestEffortClassPriority = 69; + public static int DefaultUnsolicatedGrantSize = 1000; + public static int DefaultUnsolicatedGrantsPerInterval = 3; + public static int DefaultUnsolicatedGrantInterval = 8000; + // Gate Specification Defaults + public static int DSCPToSMark = 0; + public static int Priority = 0; + public static int PreEmption = 0; + public static int GateFlags = 0; + public static int GateTOSField = 0; + public static int GateTOSMask = 0; + public static int GateClass = 0; + // Authorization life timer + public static short GateT1 = 200; + // Authorization renew timer + public static short GateT2 = 300; + // Reservation life timer + public static short GateT3 = 0; + // Reservation renew timer + public static short GateT4 = 0; + + // XXX - A new home for some of these @ org.pcmm.gates.impl.BestEffortService + public static int UGSTransmissionPolicy = 0x037F; + public static int BETransmissionPolicy = 0x0; + public static int BETrafficPriority = 0x0; + public static byte EClassifierPriority = 0x45; + + // Temporary Configure Items For Demo or Lacking Design + public static int DefaultLowBestEffortTrafficRate = 500000; + public static int DefaultVideoSourcePort = 8081; + public static int DefaultAlternateSourcePort = 1369; + // public static String DefaultCMTS = "127.0.0.1" + +/* Demo Kit Layout + public static String DefaultCMTS = "10.32.4.3"; + public static String SubscriberID = "10.32.104.2"; + public static String dstIP = "10.32.4.208"; + public static String srcIP = "10.32.154.2"; +*/ + +/* LAB Bench Layout */ + public static String DefaultCMTS = "10.32.15.3"; + public static String SubscriberID = "10.32.115.143"; + public static String dstIP = "10.32.0.234"; + public static String srcIP = "10.32.215.111"; + + public static String DefautRadius = "192.168.50.2"; + public static short srcPort = 8081; + public static short dstPort = 0; + public static int GateID1 = 0; + public static int GateID2 = 0; + public static void setGateID1(int n) { + GateID1 = n; + } + public static int getGateID1() { + return GateID1; + } + public static void setGateID2(int n) { + GateID2 = n; + } + public static int getGateID2() { + return GateID2; + } +} + +/* + * + * // if(Constants.DEBUG.isEnabled()) { } public enum Constants { DEBUG(true), + * PRINT_VARS(false); + * + * private boolean enabled; + * + * private Constants(boolean enabled) { this.enabled = enabled; } + * + * public boolean isEnabled() { return enabled; } } + */ diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMPdpAgent.java b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpAgent.java new file mode 100644 index 0000000..dbe6b07 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpAgent.java @@ -0,0 +1,411 @@ +/** + @header@ + */ + +package org.pcmm; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.ospep.COPSPepException; +import org.umu.cops.prpdp.COPSPdpAgent; +import org.umu.cops.prpdp.COPSPdpException; +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSTransceiver; +// import org.umu.cops.prpdp.COPSPdpDataProcess; +import org.pcmm.objects.MMVersionInfo; + + +/** + * Core PDP agent for provisioning + */ +public class PCMMPdpAgent extends COPSPdpAgent { + /** Well-known port for PCMM */ + public static final int WELL_KNOWN_PDP_PORT = 3918; + + private COPSPepId _pepId; + private String _pepIdString; + /** + * PEP host name + */ + private String psHost; + + /** + * PEP port + */ + private int psPort; + + private Socket socket; + + /** + * Policy data processing object + */ + private PCMMPdpDataProcess _process; + private MMVersionInfo _mminfo; + private COPSHandle _handle; + private short _transactionID; + + /** + * Creates a PDP Agent + * + * @param clientType + * COPS Client-type + * @param process + * Object to perform policy data processing + */ + public PCMMPdpAgent(short clientType, PCMMPdpDataProcess process) { + this(clientType, null, WELL_KNOWN_PDP_PORT, process); + } + + /** + * Creates a PDP Agent + * + * @param clientType + * COPS Client-type + * @param psHost + * Host to connect to + * @param psPort + * Port to connect to + * @param process + * Object to perform policy data processing + */ + public PCMMPdpAgent(short clientType, String psHost, int psPort, PCMMPdpDataProcess process) { + super(psPort, clientType, null); + this._process = process; + this.psHost = psHost; + } + + /** + * XXX -tek- This is the retooled connect. Not sure if the while forever + * loop is needed. Socket accept --> handleClientOpenMsg --> pdpConn.run() + * + * Below is new Thread(pdpConn).start(); Does that do it? + * + */ + /** + * Connects to a PDP + * + * @param psHost + * CMTS host name + * @param psPort + * CMTS port + * @return true if PDP accepts the connection; false + * otherwise + * @throws java.net.UnknownHostException + * @throws java.io.IOException + * @throws COPSException + * @throws COPSPepException + */ + public boolean connect(String psHost, int psPort) + throws UnknownHostException, IOException, COPSException, + COPSPdpException { + + this.psHost = psHost; + this.psPort = psPort; + // Create Socket and send OPN + InetAddress addr = InetAddress.getByName(psHost); + try { + socket = new Socket(addr, psPort); + } catch (IOException e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + return (false); + } + COPSDebug.err(getClass().getName(), "PDP Socket Opened"); + // Loop through for Incoming messages + + // server infinite loop + // while(true) + { + + // We're waiting for an message + try { + COPSDebug.err(getClass().getName(), + "PDP COPSTransceiver.receiveMsg "); + COPSMsg msg = COPSTransceiver.receiveMsg(socket); + if (msg.getHeader().isAClientOpen()) { + COPSDebug.err(getClass().getName(), + "PDP msg.getHeader().isAClientOpen"); + handleClientOpenMsg(socket, msg); + } else { + // COPSDebug.err(getClass().getName(), + // COPSDebug.ERROR_NOEXPECTEDMSG); + try { + socket.close(); + } catch (Exception ex) { + } + ; + } + } catch (Exception e) { // COPSException, IOException + // COPSDebug.err(getClass().getName(), + // COPSDebug.ERROR_EXCEPTION, + // "(" + socket.getInetAddress() + ":" + socket.getPort() + ")", + // e); + try { + socket.close(); + } catch (Exception ex) { + } + ; + return true; + } + } + return false; + } + + /** + * Handles a COPS client-open message + * + * @param conn + * Socket to the PEP + * @param msg + * COPSMsg holding the client-open message + * @throws COPSException + * @throws IOException + */ + private void handleClientOpenMsg(Socket conn, COPSMsg msg) + throws COPSException, IOException { + COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg; + COPSPepId pepId = cMsg.getPepId(); + + // Validate Client Type + if (msg.getHeader().getClientType() != getClientType()) { + // Unsupported client type + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg + .getHeader().getClientType()); + COPSError err = new COPSError( + COPSError.COPS_ERR_UNSUPPORTED_CLIENT_TYPE, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) { + } + + throw new COPSException("Unsupported client type"); + } + + // PEPId is mandatory + if (pepId == null) { + // Mandatory COPS object missing + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg + .getHeader().getClientType()); + COPSError err = new COPSError( + COPSError.COPS_ERR_MANDATORY_OBJECT_MISSING, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) { + } + + throw new COPSException("Mandatory COPS object missing (PEPId)"); + } + setPepId(pepId); + // Support + if ((cMsg.getClientSI() != null) ) { + _mminfo = new MMVersionInfo(cMsg + .getClientSI().getData().getData()); + System.out.println("CMTS sent MMVersion info : major:" + + _mminfo.getMajorVersionNB() + " minor:" + + _mminfo.getMinorVersionNB()); + + } else { + // Unsupported objects + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg + .getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_UNKNOWN_OBJECT, + (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) { + } + + throw new COPSException("Unsupported objects (PdpAddress, Integrity)"); + } + /* + */ + + // Connection accepted + COPSHeader ahdr = new COPSHeader(COPSHeader.COPS_OP_CAT, msg + .getHeader().getClientType()); + COPSKATimer katimer = new COPSKATimer(getKaTimer()); + COPSAcctTimer acctTimer = new COPSAcctTimer(getAcctTimer()); + COPSClientAcceptMsg acceptMsg = new COPSClientAcceptMsg(); + acceptMsg.add(ahdr); + acceptMsg.add(katimer); + if (getAcctTimer() != 0) + acceptMsg.add(acctTimer); + acceptMsg.writeData(conn); + // XXX - handleRequestMsg + try { + COPSDebug.err(getClass().getName(), "PDP COPSTransceiver.receiveMsg "); + COPSMsg rmsg = COPSTransceiver.receiveMsg(socket); + // Client-Close + if (rmsg.getHeader().isAClientClose()) { + System.out.println(((COPSClientCloseMsg) rmsg) + .getError().getDescription()); + // close the socket + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg + .getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_UNKNOWN_OBJECT, + (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) { + } + throw new COPSException("CMTS requetsed Client-Close"); + } else { + // Request + if (rmsg.getHeader().isARequest()) { + COPSReqMsg rMsg = (COPSReqMsg) rmsg; + _handle = rMsg.getClientHandle(); + } else + throw new COPSException("Can't understand request"); + + } + } catch (Exception e) { // COPSException, IOException + throw new COPSException("Error COPSTransceiver.receiveMsg"); + } + + COPSDebug.err(getClass().getName(), "PDPCOPSConnection"); + PCMMPdpConnection pdpConn = new PCMMPdpConnection(pepId, conn, _process); + pdpConn.setKaTimer(getKaTimer()); + if (getAcctTimer() != 0) + pdpConn.setAccTimer(getAcctTimer()); + + // XXX - handleRequestMsg + // XXX - check handle is valid + PCMMPdpReqStateMan man = new PCMMPdpReqStateMan(getClientType(), _handle.getId().str()); + pdpConn.getReqStateMans().put(_handle.getId().str(),man); + man.setDataProcess(_process); + try { + man.initRequestState(conn); + } catch (COPSPdpException unae) { + } + // XXX - End handleRequestMsg + + COPSDebug.err(getClass().getName(), "PDP Thread(pdpConn).start"); + new Thread(pdpConn).start(); + getConnectionMap().put(pepId.getData().str(), pdpConn); + } + + /** + * @return the _psHost + */ + public String getPsHost() { + return psHost; + } + + /** + * @param _psHost + * the _psHost to set + */ + public void setPsHost(String _psHost) { + this.psHost = _psHost; + } + + /** + * @return the _psPort + */ + public int getPsPort() { + return psPort; + } + + /** + * @param _psPort + * the _psPort to set + */ + public void setPsPort(int _psPort) { + this.psPort = _psPort; + } + + /** + * @return the socket + */ + public Socket getSocket() { + return socket; + } + + /** + * @param socket + * the socket to set + */ + public void setSocket(Socket socket) { + this.socket = socket; + } + + /** + * @return the _process + */ + public PCMMPdpDataProcess getProcess() { + return _process; + } + + /** + * @param _process + * the _process to set + */ + public void setProcess(PCMMPdpDataProcess _process) { + this._process = _process; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the PepId + * @return COPSPepId + */ + public COPSPepId getPepId() { + return _pepId; + } + + public String getPepIdString() { + return _pepIdString; + } + + /** + * Sets the PepId + * @param COPSPepId + */ + public void setPepId(COPSPepId pepId) { + _pepId = pepId; + _pepIdString = pepId.getData().str(); + } + /* + * (non-Javadoc) + * + * @see org.pcmm.rcd.IPCMMClient#isConnected() + */ + public boolean isConnected() { + return socket != null && socket.isConnected(); + } + + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMPdpConnection.java b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpConnection.java new file mode 100644 index 0000000..ceb5ccd --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpConnection.java @@ -0,0 +1,553 @@ +/* + @header@ + */ + +package org.pcmm; + +import java.io.IOException; +import java.net.Socket; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.prpdp.COPSPdpException; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKAMsg; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; +import org.umu.cops.stack.COPSTransceiver; + +/** + * Class for managing an provisioning connection at the PDP side. + */ +public class PCMMPdpConnection implements Runnable { + + /** + Socket connected to PEP + */ + private Socket _sock; + + /** + PEP identifier + */ + private COPSPepId _pepId; + + /** + Time of the latest keep-alive sent + */ + private Date _lastKa; + + /** + Opcode of the latest message sent + */ + private byte _lastmessage; + + /** + * Time of the latest keep-alive received + */ + protected Date _lastRecKa; + + /** + Maps a Client Handle to a Handler + */ + protected Hashtable _managerMap; + // map < String(COPSHandle), COPSPdpHandler> HandlerMap; + + /** + * PDP policy data processor class + */ + protected PCMMPdpDataProcess _process; + + /** + Accounting timer value (secs) + */ + protected short _acctTimer; + + /** + Keep-alive timer value (secs) + */ + protected short _kaTimer; + + /** + COPS error returned by PEP + */ + protected COPSError _error; + + /** + * Creates a new PDP connection + * + * @param pepId PEP-ID of the connected PEP + * @param sock Socket connected to PEP + * @param process Object for processing policy data + */ + public PCMMPdpConnection(COPSPepId pepId, Socket sock, PCMMPdpDataProcess process) { + _sock = sock; + _pepId = pepId; + + _lastKa = new Date(); + _lastmessage = COPSHeader.COPS_OP_OPN; + _managerMap = new Hashtable(20); + + _kaTimer = 120; + _process = process; + } + + /** + * Gets the time of that latest keep-alive sent + * @return Time of that latest keep-alive sent + */ + public Date getLastKAlive() { + return _lastKa; + } + + /** + * Sets the keep-alive timer value + * @param kaTimer Keep-alive timer value (secs) + */ + public void setKaTimer(short kaTimer) { + _kaTimer = kaTimer; + } + + /** + * Gets the keep-alive timer value + * @return Keep-alive timer value (secs) + */ + public short getKaTimer() { + return _kaTimer; + } + + /** + * Sets the accounting timer value + * @param acctTimer Accounting timer value (secs) + */ + public void setAccTimer(short acctTimer) { + _acctTimer = acctTimer; + } + + /** + * Gets the accounting timer value + * @return Accounting timer value (secs) + */ + public short getAcctTimer() { + return _acctTimer; + } + + /** + * Gets the latest COPS message + * @return Code of the latest message sent + */ + public byte getLastMessage() { + return _lastmessage; + } + + /** + * Gets active handles + * @return An Enumeration holding all active handles + */ + public Enumeration getHandles() { + return _managerMap.keys(); + } + + /** + * Gets the handle map + * @return A Hashtable holding the handle map + */ + public Hashtable getReqStateMans() { + return _managerMap; + } + + /** + * Gets the PEP-ID + * @return The ID of the PEP, as a String + */ + public String getPepId() { + return _pepId.getData().str(); + } + + /** + * Checks whether the socket to the PEP is closed or not + * @return true if closed, false otherwise + */ + public boolean isClosed() { + return _sock.isClosed(); + } + + /** + * Closes the socket to the PEP + * @throws IOException + */ + protected void close() + throws IOException { + _sock.close(); + } + + /** + * Gets the socket to the PEP + * @return Socket connected to the PEP + */ + public Socket getSocket() { + return _sock; + } + + /** + * Main loop + */ + public void run () { + Date _lastSendKa = new Date(); + _lastRecKa = new Date(); + try { + while (!_sock.isClosed()) { + if (_sock.getInputStream().available() != 0) { + _lastmessage = processMessage(_sock); + _lastRecKa = new Date(); + } + + // Keep Alive + if (_kaTimer > 0) { + // Timeout at PDP + int _startTime = (int) (_lastRecKa.getTime()); + int cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > _kaTimer*1000) { + _sock.close(); + // Notify all Request State Managers + notifyNoKAAllReqStateMan(); + } + + // Send to PEP + _startTime = (int) (_lastSendKa.getTime()); + cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > ((_kaTimer*3/4)*1000)) { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA); + COPSKAMsg msg = new COPSKAMsg(); + + msg.add(hdr); + + COPSTransceiver.sendMsg(msg, _sock); + _lastSendKa = new Date(); + } + } + + try { + Thread.sleep(500); + } catch (Exception e) {}; + + } + } catch (Exception e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } + + // connection closed by server + // COPSDebug.out(getClass().getName(),"Connection closed by client"); + try { + _sock.close(); + } catch (IOException e) {}; + + // Notify all Request State Managers + try { + notifyCloseAllReqStateMan(); + } catch (COPSPdpException e) {}; + } + + /** + * Gets a COPS message from the socket and processes it + * @param conn Socket connected to the PEP + * @return Type of COPS message + */ + private byte processMessage(Socket conn) + throws COPSPdpException, COPSException, IOException { + COPSMsg msg = COPSTransceiver.receiveMsg(conn); + + if (msg.getHeader().isAClientClose()) { + handleClientCloseMsg(conn, msg); + return COPSHeader.COPS_OP_CC; + } else if (msg.getHeader().isAKeepAlive()) { + handleKeepAliveMsg(conn, msg); + return COPSHeader.COPS_OP_KA; + } else if (msg.getHeader().isARequest()) { + handleRequestMsg(conn, msg); + return COPSHeader.COPS_OP_REQ; + } else if (msg.getHeader().isAReport()) { + handleReportMsg(conn, msg); + return COPSHeader.COPS_OP_RPT; + } else if (msg.getHeader().isADeleteReq()) { + handleDeleteRequestMsg(conn, msg); + return COPSHeader.COPS_OP_DRQ; + } else if (msg.getHeader().isASyncComplete()) { + handleSyncComplete(conn, msg); + return COPSHeader.COPS_OP_SSC; + } else { + throw new COPSPdpException("Message not expected (" + msg.getHeader().getOpCode() + ")."); + } + } + + /** + * Handle Client Close Message, close the passed connection + * + * @param conn a Socket + * @param msg a COPSMsg + * + * + * ::= + * + * [] + * + * Not support [] + * + */ + private void handleClientCloseMsg(Socket conn, COPSMsg msg) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg; + _error = cMsg.getError(); + + // COPSDebug.out(getClass().getName(),"Got close request, closing connection " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]"); + + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + conn.close(); + } catch (Exception unae) { }; + } + + /** + * Gets the occurred COPS Error + * @return COPSError object + */ + protected COPSError getError() { + return _error; + } + + /** + * Handle Keep Alive Message + * + * ::= + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleKeepAliveMsg(Socket conn, COPSMsg msg) { + COPSKAMsg cMsg = (COPSKAMsg) msg; + + COPSKAMsg kaMsg = (COPSKAMsg) msg; + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + kaMsg.writeData(conn); + } catch (Exception unae) { }; + } + + /** + * Handle Delete Request Message + * + * ::= + * + * + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleDeleteRequestMsg(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSDeleteMsg cMsg = (COPSDeleteMsg) msg; + // COPSDebug.out(getClass().getName(),"Removing ClientHandle for " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Reason " + cMsg.getReason().getDescription() + "]"); + + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + // Delete clientHandler + if (_managerMap.remove(cMsg.getClientHandle().getId().str()) == null) { + // COPSDebug.out(getClass().getName(),"Missing for ClientHandle " + + // cMsg.getClientHandle().getId().getData()); + } + + PCMMPdpReqStateMan man = (PCMMPdpReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processDeleteRequestState(cMsg); + } + + } + + /** + * Handle Request Message + * + * ::= + * + * + * *() + * [] + * ::= <*( )> + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleRequestMsg(Socket conn, COPSMsg msg) + throws COPSPdpException { + + COPSReqMsg reqMsg = (COPSReqMsg) msg; + COPSContext cntxt = reqMsg.getContext(); + COPSHeader header = reqMsg.getHeader(); + //short reqType = cntxt.getRequestType(); + short cType = header.getClientType(); + + // Support + if (reqMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + PCMMPdpReqStateMan man; + man = (PCMMPdpReqStateMan) _managerMap.get(reqMsg.getClientHandle().getId().str()); + if (man == null) { + + man = new PCMMPdpReqStateMan(cType, reqMsg.getClientHandle().getId().str()); + _managerMap.put(reqMsg.getClientHandle().getId().str(),man); + man.setDataProcess(_process); + man.initRequestState(_sock); + + // COPSDebug.out(getClass().getName(),"createHandler called, clientType=" + + // header.getClientType() + " msgType=" + + // cntxt.getMessageType() + ", connId=" + conn.toString()); + } + + man.processRequest(reqMsg); + } + + /** + * Handle Report Message + * + * ::= + * + * + * *() + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleReportMsg(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSReportMsg repMsg = (COPSReportMsg) msg; + // COPSHandle handle = repMsg.getClientHandle(); + // COPSHeader header = repMsg.getHeader(); + + // Support + if (repMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + PCMMPdpReqStateMan man = (PCMMPdpReqStateMan) _managerMap.get(repMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processReport(repMsg); + } + } + + /** + * Method handleSyncComplete + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleSyncComplete(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg; + // COPSHandle handle = cMsg.getClientHandle(); + // COPSHeader header = cMsg.getHeader(); + + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + PCMMPdpReqStateMan man = (PCMMPdpReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processSyncComplete(cMsg); + } + } + + /** + * Requests a COPS sync from the PEP + * @throws COPSException + * @throws COPSPdpException + */ + protected void syncAllRequestState() + throws COPSException, COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + PCMMPdpReqStateMan man = (PCMMPdpReqStateMan) _managerMap.get(handle); + + man.syncRequestState(); + } + } + } + + private void notifyCloseAllReqStateMan() + throws COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + PCMMPdpReqStateMan man = (PCMMPdpReqStateMan) _managerMap.get(handle); + + man.processClosedConnection(_error); + } + } + } + + private void notifyNoKAAllReqStateMan() + throws COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + PCMMPdpReqStateMan man = (PCMMPdpReqStateMan) _managerMap.get(handle); + + man.processNoKAConnection(); + } + } + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMPdpDataProcess.java b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpDataProcess.java new file mode 100644 index 0000000..e1e162a --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpDataProcess.java @@ -0,0 +1,208 @@ +/** + @header@ + */ + +package org.pcmm; + +import java.util.Hashtable; + +import org.pcmm.gates.ITransactionID; +import org.pcmm.gates.impl.PCMMGateReq; +// import org.umu.cops.prpdp.COPSPdpDataProcess; +import org.umu.cops.stack.COPSError; + + +public class PCMMPdpDataProcess { // extends COPSPdpDataProcess + private Hashtable installPolicy; + private Hashtable removePolicy; + + public PCMMPdpDataProcess() { + } + + /** + * PDPAgent gets the policies to delete from PEP + * + * @param man + * @return + */ + public Hashtable getRemovePolicy(PCMMPdpReqStateMan man) { + return removePolicy; + } + + /** + * PDPAgent gets the policies to be installed in PEP + * + * @param man + * @return + */ + public Hashtable getInstallPolicy(PCMMPdpReqStateMan man) { + return installPolicy; + } + + /** + * PEP configuration items for sending inside the request + * + * @param man + * @param reqSIs + */ + public void setClientData(PCMMPdpReqStateMan man, Hashtable reqSIs) { + + System.out.println(getClass().getName() + ": " + "Request Info"); + /* + for (Enumeration e = reqSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) reqSIs.get(strprid); + + // Check PRID-EPD + // .... + System.out.println(getClass().getName() + ": " + "PRID: " + strprid); + System.out.println(getClass().getName() + ": " + "EPD: " + strepd); + } + + // Create policies to be deleted + // .... + + // Create policies to be installed + String prid = new String(""); + String epd = new String(""); + installPolicy.put(prid, epd); + */ + } + + /** + * Fail report received + * + * @param man + * @param reportSIs + */ + public void failReport(PCMMPdpReqStateMan man, PCMMGateReq gateMsg) { + + System.out.println(getClass().getName()+ ": " + "Fail Report notified."); + System.out.println(getClass().getName()+ ": " + gateMsg.getError().toString()); + + /* + + System.out.println(getClass().getName() + ": " + "Report Info"); + for (Enumeration e = reportSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) reportSIs.get(strprid); + + // Check PRID-EPD + // .... + System.out.println(getClass().getName()+ ": " + "PRID: " + strprid); + System.out.println(getClass().getName()+ ": " + "EPD: " + strepd); + } + */ + } + + /** + * Positive report received + * + * @param man + * @param reportSIs + */ + public void successReport(PCMMPdpReqStateMan man, PCMMGateReq gateMsg) { + System.out.println(getClass().getName()+ ": " + "Success Report notified."); + + if ( gateMsg.getTransactionID().getGateCommandType() == ITransactionID.GateDeleteAck ) { + System.out.println(getClass().getName()+ ": GateDeleteAck "); + System.out.println(getClass().getName()+ ": GateID = " + gateMsg.getGateID().getGateID()); + if (gateMsg.getGateID().getGateID() == PCMMGlobalConfig.getGateID1()) + PCMMGlobalConfig.setGateID1(0); + if (gateMsg.getGateID().getGateID() == PCMMGlobalConfig.getGateID2()) + PCMMGlobalConfig.setGateID2(0); + + } + if ( gateMsg.getTransactionID().getGateCommandType() == ITransactionID.GateSetAck ) { + System.out.println(getClass().getName()+ ": GateSetAck "); + System.out.println(getClass().getName()+ ": GateID = " + gateMsg.getGateID().getGateID()); + if (0 == PCMMGlobalConfig.getGateID1()) + PCMMGlobalConfig.setGateID1(gateMsg.getGateID().getGateID()); + if (0 == PCMMGlobalConfig.getGateID2()) + PCMMGlobalConfig.setGateID2(gateMsg.getGateID().getGateID()); + } + + /* + System.out.println(getClass().getName()+ ": " + "Report Info"); + for (Enumeration e = reportSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) reportSIs.get(strprid); + + // Check PRID-EPD + // .... + System.out.println(getClass().getName()+ ": " + "PRID: " + strprid); + System.out.println(getClass().getName()+ ": " + "EPD: " + strepd); + } + */ + + } + + /** + * Accounting report received + * + * @param man + * @param reportSIs + */ + public void acctReport(PCMMPdpReqStateMan man, PCMMGateReq gateMsg) { + System.out.println(getClass().getName()+ ": " + "Acct Report notified."); + + /* + System.out.println(getClass().getName()+ ": " + "Report Info"); + for (Enumeration e = reportSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) reportSIs.get(strprid); + + // Check PRID-EPD + // .... + System.out.println(getClass().getName()+ ": " + "PRID: " + strprid); + System.out.println(getClass().getName()+ ": " + "EPD: " + strepd); + } + */ + } + + /** + * Notifies that an Accounting report is missing + * + * @param man + */ + public void notifyNoAcctReport(PCMMPdpReqStateMan man) { + //To change body of implemented methods use File | Settings | File Templates. + } + + /** + * Notifies that a KeepAlive message is missing + * + * @param man + */ + public void notifyNoKAliveReceived(PCMMPdpReqStateMan man) { + //To change body of implemented methods use File | Settings | File Templates. + } + + /** + * PEP closed the connection + * + * @param man + * @param error + */ + public void notifyClosedConnection(PCMMPdpReqStateMan man, COPSError error) { + System.out.println(getClass().getName() + ": " + "Connection was closed by PEP"); + } + + /** + * Delete request state received + * + * @param man + */ + public void notifyDeleteRequestState(PCMMPdpReqStateMan man) { + //To change body of implemented methods use File | Settings | File Templates. + } + + /** + * Closes request state + * + * @param man + */ + public void closeRequestState(PCMMPdpReqStateMan man) { + //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMPdpMsgSender.java b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpMsgSender.java new file mode 100644 index 0000000..89e7f44 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpMsgSender.java @@ -0,0 +1,981 @@ +/** + @header@ + */ + +package org.pcmm; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import org.pcmm.gates.IAMID; +import org.pcmm.gates.IClassifier; +import org.pcmm.gates.IExtendedClassifier; +import org.pcmm.gates.IGateID; +import org.pcmm.gates.IGateSpec; +import org.pcmm.gates.IGateSpec.DSCPTOS; +import org.pcmm.gates.IGateSpec.Direction; +import org.pcmm.gates.IPCMMGate; +import org.pcmm.gates.ISubscriberID; +import org.pcmm.gates.ITrafficProfile; +import org.pcmm.gates.ITransactionID; +import org.pcmm.gates.impl.AMID; +import org.pcmm.gates.impl.BestEffortService; +import org.pcmm.gates.impl.Classifier; +import org.pcmm.gates.impl.ExtendedClassifier; +import org.pcmm.gates.impl.GateID; +import org.pcmm.gates.impl.GateSpec; +import org.pcmm.gates.impl.PCMMGateReq; +import org.pcmm.gates.impl.SubscriberID; +import org.pcmm.gates.impl.TransactionID; +import org.umu.cops.prpdp.COPSPdpException; +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSObjHeader; +//temp +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSSyncStateMsg; +import org.umu.cops.stack.COPSTransceiver; +//pcmm +/* + * Example of an UNSOLICITED decision + * + * = + * + * = | | | + * | | + * = [] + * [] [] + * [] [][] [] + */ + +/** + * COPS message transceiver class for provisioning connections at the PDP side. + */ +public class PCMMPdpMsgSender { + + /** + * Socket connected to PEP + */ + protected Socket _sock; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular PEP's request + * for a client-type + */ + protected COPSHandle _handle; + + /** + * + */ + protected short _transactionID; + protected short _classifierID; + // XXX - this does not need to be here + protected int _gateID; + + /** + * Creates a PCMMPdpMsgSender + * + * @param clientType + * COPS client-type + * @param clientHandle + * Client handle + * @param sock + * Socket to the PEP + */ + public PCMMPdpMsgSender(short clientType, COPSHandle clientHandle, + Socket sock) { + // COPS Handle + _handle = clientHandle; + _clientType = clientType; + + _transactionID = 0; + _classifierID = 0; + _sock = sock; + } + + public PCMMPdpMsgSender(short clientType, short tID, + COPSHandle clientHandle, Socket sock) { + // COPS Handle + _handle = clientHandle; + _clientType = clientType; + _transactionID = tID; + _classifierID = 0; + _sock = sock; + } + + /** + * Gets the client handle + * + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the client-type + * + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Gets the transaction-id + * + * @return transaction-id value + */ + public short getTransactionID() { + return _transactionID; + } + + + /** + * Sends a PCMM GateSet COPS Decision message + * + * @param + * @throws COPSPdpException + */ + public void sendGateSet(IPCMMGate gate) + throws COPSPdpException { + // Common Header with the same ClientType as the request + + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + ITransactionID trID = new TransactionID(); + + handle.setId(getClientHandle().getId()); + + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateSet); + _transactionID = (short) (_transactionID == 0 ? (short) (Math.random() * hashCode()) + : _transactionID); + trID.setTransactionIdentifier(_transactionID); + + gate.setTransactionID(trID); + + + // new pcmm specific clientsi + COPSClientSI clientSD = new COPSClientSI(COPSObjHeader.COPS_DEC, (byte) 4); + byte[] data = gate.getData(); + clientSD.setData(new COPSData(data, 0, data.length)); + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + COPSDecision install = new COPSDecision(); + install.setCmdCode(COPSDecision.DEC_INSTALL); + install.setFlags(COPSDecision.F_REQERROR); + decisionMsg.addDecision(install, cntxt); + decisionMsg.add(clientSD); // setting up the gate + /* + try { + decisionMsg.dump(System.out); + } catch (IOException unae) { + System.out.println("Error dumping " + unae.getMessage()); + } + */ + + } catch (COPSException e) { + System.out.println("Error making Msg" + e.getMessage()); + } + + // ** Send the GateSet Decision + // ** + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + System.out.println("Failed to send the decision, reason: " + + e.getMessage()); + } + + } + + /** + * Sends a PCMM GateSet COPS Decision message + * + * @param + * @throws COPSPdpException + */ + public void sendGateSetDemo(int num) + throws COPSPdpException { + + // Common Header with the same ClientType as the request + + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + + IPCMMGate gate = new PCMMGateReq(); + ITransactionID trID = new TransactionID(); + + IAMID amid = new AMID(); + ISubscriberID subscriberID = new SubscriberID(); + IGateSpec gateSpec = new GateSpec(); + IClassifier classifier = new Classifier(); + IExtendedClassifier eclassifier = new ExtendedClassifier(); + int TrafficRate = 0; + + if (num == 1) + TrafficRate = PCMMGlobalConfig.DefaultBestEffortTrafficRate; + else + TrafficRate = PCMMGlobalConfig.DefaultLowBestEffortTrafficRate; + + ITrafficProfile trafficProfile = new BestEffortService( + (byte) 7); //BestEffortService.DEFAULT_ENVELOP); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setMaximumTrafficBurst( + BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setRequestTransmissionPolicy( + PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setMaximumSustainedTrafficRate( + TrafficRate); + // PCMMGlobalConfig.DefaultLowBestEffortTrafficRate ); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setMaximumTrafficBurst( + BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setRequestTransmissionPolicy( + PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setMaximumSustainedTrafficRate( + TrafficRate); + // PCMMGlobalConfig.DefaultLowBestEffortTrafficRate ); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setMaximumTrafficBurst( + BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setRequestTransmissionPolicy( + PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setMaximumSustainedTrafficRate( + TrafficRate); + // PCMMGlobalConfig.DefaultLowBestEffortTrafficRate ); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + + + // new pcmm specific clientsi + COPSClientSI clientSD = new COPSClientSI(COPSObjHeader.COPS_DEC, (byte) 4); + + handle.setId(getClientHandle().getId()); + + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateSet); + _transactionID = (short) (_transactionID == 0 ? (short) (Math.random() * hashCode()) + : _transactionID); + trID.setTransactionIdentifier(_transactionID); + + amid.setApplicationType((short) 1); + amid.setApplicationMgrTag((short) 1); + gateSpec.setDirection(Direction.UPSTREAM); + gateSpec.setDSCP_TOSOverwrite(DSCPTOS.OVERRIDE); + gateSpec.setTimerT1(PCMMGlobalConfig.GateT1); + gateSpec.setTimerT2(PCMMGlobalConfig.GateT2); + gateSpec.setTimerT3(PCMMGlobalConfig.GateT3); + gateSpec.setTimerT4(PCMMGlobalConfig.GateT4); + + // XXX - if the version major is less than 4 we need to use Classifier + if (true) { + //eclassifier.setProtocol(IClassifier.Protocol.NONE); + eclassifier.setProtocol(IClassifier.Protocol.TCP); + try { + InetAddress subIP = InetAddress + .getByName(PCMMGlobalConfig.SubscriberID); + InetAddress srcIP = InetAddress + .getByName(PCMMGlobalConfig.srcIP); + InetAddress dstIP = InetAddress + .getByName(PCMMGlobalConfig.dstIP); + InetAddress mask = InetAddress.getByName("0.0.0.0"); + subscriberID.setSourceIPAddress(subIP); + eclassifier.setSourceIPAddress(srcIP); + eclassifier.setDestinationIPAddress(dstIP); + eclassifier.setIPDestinationMask(mask); + eclassifier.setIPSourceMask(mask); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + eclassifier.setSourcePortStart(PCMMGlobalConfig.srcPort); + eclassifier.setSourcePortEnd(PCMMGlobalConfig.srcPort); + eclassifier.setDestinationPortStart(PCMMGlobalConfig.dstPort); + eclassifier.setDestinationPortEnd(PCMMGlobalConfig.dstPort); + eclassifier.setActivationState((byte) 0x01); + // check if we have a stored value of classifierID else we just + // create + // one + // eclassifier.setClassifierID((short) 0x01); + eclassifier.setClassifierID((short) (_classifierID == 0 ? Math + .random() * hashCode() : _classifierID)); + // XXX - testie + // eclassifier.setClassifierID((short) 1); + + eclassifier.setAction((byte) 0x00); + // XXX - temp default until Gate Modify is hacked in + // eclassifier.setPriority(PCMMGlobalConfig.EClassifierPriority); + eclassifier.setPriority((byte) 65); + + } else { + classifier.setProtocol(IClassifier.Protocol.TCP); + try { + InetAddress subIP = InetAddress + .getByName(PCMMGlobalConfig.SubscriberID); + InetAddress srcIP = InetAddress + .getByName(PCMMGlobalConfig.srcIP); + InetAddress dstIP = InetAddress + .getByName(PCMMGlobalConfig.dstIP); + subscriberID.setSourceIPAddress(subIP); + classifier.setSourceIPAddress(srcIP); + classifier.setDestinationIPAddress(dstIP); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + classifier.setSourcePort(PCMMGlobalConfig.srcPort); + classifier.setDestinationPort(PCMMGlobalConfig.dstPort); + } + + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateSpec(gateSpec); + gate.setTrafficProfile(trafficProfile); + gate.setClassifier(eclassifier); + + byte[] data = gate.getData(); + + // new pcmm specific clientsi + clientSD.setData(new COPSData(data, 0, data.length)); + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + COPSDecision install = new COPSDecision(); + install.setCmdCode(COPSDecision.DEC_INSTALL); + install.setFlags(COPSDecision.F_REQERROR); + decisionMsg.addDecision(install, cntxt); + decisionMsg.add(clientSD); // setting up the gate + /* + try { + decisionMsg.dump(System.out); + } catch (IOException unae) { + System.out.println("Error dumping " + unae.getMessage()); + } + */ + + } catch (COPSException e) { + System.out.println("Error making Msg" + e.getMessage()); + } + + // ** Send the GateSet Decision + // ** + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + System.out.println("Failed to send the decision, reason: " + + e.getMessage()); + } + + } + /** + * Sends a PCMM GateSet COPS Decision message + * + * @param + * @throws COPSPdpException + */ + public void sendGateSetBestEffortWithExtendedClassifier() + throws COPSPdpException { + // Common Header with the same ClientType as the request + + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + + IPCMMGate gate = new PCMMGateReq(); + ITransactionID trID = new TransactionID(); + + IAMID amid = new AMID(); + ISubscriberID subscriberID = new SubscriberID(); + IGateSpec gateSpec = new GateSpec(); + IClassifier classifier = new Classifier(); + IExtendedClassifier eclassifier = new ExtendedClassifier(); + + // XXX check if other values should be provided + // + ITrafficProfile trafficProfile = new BestEffortService( + (byte) 7); //BestEffortService.DEFAULT_ENVELOP); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setMaximumTrafficBurst( + BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setRequestTransmissionPolicy( + PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setMaximumSustainedTrafficRate( + PCMMGlobalConfig.DefaultLowBestEffortTrafficRate ); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setMaximumTrafficBurst( + BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setRequestTransmissionPolicy( + PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getReservedEnvelop() + .setMaximumSustainedTrafficRate( + PCMMGlobalConfig.DefaultLowBestEffortTrafficRate ); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setMaximumTrafficBurst( + BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setRequestTransmissionPolicy( + PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getCommittedEnvelop() + .setMaximumSustainedTrafficRate( + PCMMGlobalConfig.DefaultLowBestEffortTrafficRate ); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + + + // new pcmm specific clientsi + COPSClientSI clientSD = new COPSClientSI(COPSObjHeader.COPS_DEC, + (byte) 4); + + handle.setId(getClientHandle().getId()); + + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateSet); + _transactionID = (short) (_transactionID == 0 ? (short) (Math.random() * hashCode()) + : _transactionID); + trID.setTransactionIdentifier(_transactionID); + + amid.setApplicationType((short) 1); + amid.setApplicationMgrTag((short) 1); + gateSpec.setDirection(Direction.UPSTREAM); + gateSpec.setDSCP_TOSOverwrite(DSCPTOS.OVERRIDE); + gateSpec.setTimerT1(PCMMGlobalConfig.GateT1); + gateSpec.setTimerT2(PCMMGlobalConfig.GateT2); + gateSpec.setTimerT3(PCMMGlobalConfig.GateT3); + gateSpec.setTimerT4(PCMMGlobalConfig.GateT4); + + // XXX - if the version major is less than 4 we need to use Classifier + if (true) { + //eclassifier.setProtocol(IClassifier.Protocol.NONE); + eclassifier.setProtocol(IClassifier.Protocol.TCP); + try { + InetAddress subIP = InetAddress + .getByName(PCMMGlobalConfig.SubscriberID); + InetAddress srcIP = InetAddress + .getByName(PCMMGlobalConfig.srcIP); + InetAddress dstIP = InetAddress + .getByName(PCMMGlobalConfig.dstIP); + InetAddress mask = InetAddress.getByName("0.0.0.0"); + subscriberID.setSourceIPAddress(subIP); + eclassifier.setSourceIPAddress(srcIP); + eclassifier.setDestinationIPAddress(dstIP); + eclassifier.setIPDestinationMask(mask); + eclassifier.setIPSourceMask(mask); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + eclassifier.setSourcePortStart(PCMMGlobalConfig.srcPort); + eclassifier.setSourcePortEnd(PCMMGlobalConfig.srcPort); + eclassifier.setDestinationPortStart(PCMMGlobalConfig.dstPort); + eclassifier.setDestinationPortEnd(PCMMGlobalConfig.dstPort); + eclassifier.setActivationState((byte) 0x01); + // check if we have a stored value of classifierID else we just + // create + // one + // eclassifier.setClassifierID((short) 0x01); + eclassifier.setClassifierID((short) (_classifierID == 0 ? Math + .random() * hashCode() : _classifierID)); + // XXX - testie + // eclassifier.setClassifierID((short) 1); + + eclassifier.setAction((byte) 0x00); + // XXX - temp default until Gate Modify is hacked in + // eclassifier.setPriority(PCMMGlobalConfig.EClassifierPriority); + eclassifier.setPriority((byte) 65); + + } else { + classifier.setProtocol(IClassifier.Protocol.TCP); + try { + InetAddress subIP = InetAddress + .getByName(PCMMGlobalConfig.SubscriberID); + InetAddress srcIP = InetAddress + .getByName(PCMMGlobalConfig.srcIP); + InetAddress dstIP = InetAddress + .getByName(PCMMGlobalConfig.dstIP); + subscriberID.setSourceIPAddress(subIP); + classifier.setSourceIPAddress(srcIP); + classifier.setDestinationIPAddress(dstIP); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + classifier.setSourcePort(PCMMGlobalConfig.srcPort); + classifier.setDestinationPort(PCMMGlobalConfig.dstPort); + } + + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateSpec(gateSpec); + gate.setTrafficProfile(trafficProfile); + gate.setClassifier(eclassifier); + + byte[] data = gate.getData(); + + // new pcmm specific clientsi + clientSD.setData(new COPSData(data, 0, data.length)); + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + COPSDecision install = new COPSDecision(); + install.setCmdCode(COPSDecision.DEC_INSTALL); + install.setFlags(COPSDecision.F_REQERROR); + decisionMsg.addDecision(install, cntxt); + decisionMsg.add(clientSD); // setting up the gate + /* + try { + decisionMsg.dump(System.out); + } catch (IOException unae) { + System.out.println("Error dumping " + unae.getMessage()); + } + */ + + } catch (COPSException e) { + System.out.println("Error making Msg" + e.getMessage()); + } + + // ** Send the GateSet Decision + // ** + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + System.out.println("Failed to send the decision, reason: " + + e.getMessage()); + } + + } + + + public boolean handleGateReport(Socket socket) throws COPSPdpException { + try { + // waits for the gate-set-ack or error + COPSMsg responseMsg = COPSTransceiver.receiveMsg(socket); + if (responseMsg.getHeader().isAReport()) { + System.out.println("processing received report from CMTS"); + COPSReportMsg reportMsg = (COPSReportMsg) responseMsg; + if (reportMsg.getClientSI().size() == 0) { + return false; + } + COPSClientSI clientSI = (COPSClientSI) reportMsg.getClientSI() + .elementAt(0); + IPCMMGate responseGate = new PCMMGateReq(clientSI.getData() + .getData()); + if (responseGate.getTransactionID() != null + && responseGate.getTransactionID().getGateCommandType() == ITransactionID.GateSetAck) { + System.out.println("the CMTS has sent a Gate-Set-Ack response"); + // here CMTS responded that he acknowledged the Gate-Set + // TODO do further check of Gate-Set-Ack GateID etc... + _gateID = responseGate.getGateID().getGateID(); + return true; + } else { + return false; + } + } + return false; + } catch (Exception e) { // COPSException, IOException + throw new COPSPdpException("Error COPSTransceiver.receiveMsg"); + } + } + + + /** + * Sends a PCMM GateSet COPS Decision message + * + * @param + * @throws COPSPdpException + */ + public void sendGateSet() throws COPSPdpException { + // Common Header with the same ClientType as the request + + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + + IPCMMGate gate = new PCMMGateReq(); + ITransactionID trID = new TransactionID(); + + IAMID amid = new AMID(); + ISubscriberID subscriberID = new SubscriberID(); + IGateSpec gateSpec = new GateSpec(); + IClassifier classifier = new Classifier(); + // XXX check if other values should be provided + ITrafficProfile trafficProfile = new BestEffortService( + BestEffortService.DEFAULT_ENVELOP); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setMaximumTrafficBurst( + BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop() + .setRequestTransmissionPolicy( + PCMMGlobalConfig.BETransmissionPolicy); + + // new pcmm specific clientsi + COPSClientSI clientSD = new COPSClientSI(COPSObjHeader.COPS_DEC, + (byte) 4); + + handle.setId(getClientHandle().getId()); + // byte[] content = "1234".getBytes(); + + // handle.setId(new COPSData(content, 0, content.length)); + + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateSet); + _transactionID = (short) (_transactionID == 0 ? (short) (Math.random() * hashCode()) + : _transactionID); + trID.setTransactionIdentifier(_transactionID); + + amid.setApplicationType((short) 1); + amid.setApplicationMgrTag((short) 1); + gateSpec.setDirection(Direction.UPSTREAM); + gateSpec.setDSCP_TOSOverwrite(DSCPTOS.OVERRIDE); + gateSpec.setTimerT1(PCMMGlobalConfig.GateT1); + gateSpec.setTimerT2(PCMMGlobalConfig.GateT2); + gateSpec.setTimerT3(PCMMGlobalConfig.GateT3); + gateSpec.setTimerT4(PCMMGlobalConfig.GateT4); + + /* + * ((DOCSISServiceClassNameTrafficProfile) trafficProfile) + * .setServiceClassName("S_up"); + */ + + classifier.setProtocol(IClassifier.Protocol.TCP); + try { + InetAddress subIP = InetAddress.getByName(PCMMGlobalConfig.SubscriberID); + InetAddress srcIP = InetAddress.getByName(PCMMGlobalConfig.srcIP); + InetAddress dstIP = InetAddress.getByName(PCMMGlobalConfig.dstIP); + subscriberID.setSourceIPAddress(subIP); + classifier.setSourceIPAddress(srcIP); + classifier.setDestinationIPAddress(dstIP); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + classifier.setSourcePort(PCMMGlobalConfig.srcPort); + classifier.setDestinationPort(PCMMGlobalConfig.dstPort); + + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateSpec(gateSpec); + gate.setTrafficProfile(trafficProfile); + gate.setClassifier(classifier); + + byte[] data = gate.getData(); + + // new pcmm specific clientsi + clientSD.setData(new COPSData(data, 0, data.length)); + + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + COPSDecision install = new COPSDecision(); + install.setCmdCode(COPSDecision.DEC_INSTALL); + install.setFlags(COPSDecision.F_REQERROR); + decisionMsg.addDecision(install, cntxt); + decisionMsg.add(clientSD); // setting up the gate + /* + try { + decisionMsg.dump(System.out); + } catch (IOException unae) { + System.out.println("Error dumping " + unae.getMessage()); + } + */ + + } catch (COPSException e) { + System.out.println("Error making Msg" + e.getMessage()); + } + + // ** Send the GateSet Decision + // ** + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + System.out.println("Failed to send the decision, reason: " + + e.getMessage()); + } + + } + + /** + * Sends a message asking that the request state be deleted + * + * @throws COPSPdpException + */ + public void sendGateDelete(int gID) throws COPSPdpException { + /* + * Example of an UNSOLICITED decision = = | | | + * | | = + * + */ + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + + IPCMMGate gate = new PCMMGateReq(); + ITransactionID trID = new TransactionID(); + + IAMID amid = new AMID(); + ISubscriberID subscriberID = new SubscriberID(); + IGateSpec gateSpec = new GateSpec(); + IGateID gateID = new GateID(); + + // new pcmm specific clientsi + COPSClientSI clientSD = new COPSClientSI(COPSObjHeader.COPS_DEC, (byte) 4); + + handle.setId(getClientHandle().getId()); + + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateDelete); + _transactionID = (short) (_transactionID == 0 ? (short) (Math.random() * hashCode()) + : _transactionID); + trID.setTransactionIdentifier(_transactionID); + + amid.setApplicationType((short) 1); + amid.setApplicationMgrTag((short) 1); + gateID.setGateID(gID); + + try { + InetAddress subIP = InetAddress.getByName(PCMMGlobalConfig.SubscriberID); + subscriberID.setSourceIPAddress(subIP); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateID(gateID); + + // XXX - GateID + byte[] data = gate.getData(); + + // new pcmm specific clientsi + clientSD.setData(new COPSData(data, 0, data.length)); + + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + COPSDecision install = new COPSDecision(); + install.setCmdCode(COPSDecision.DEC_INSTALL); + install.setFlags(COPSDecision.F_REQERROR); + decisionMsg.addDecision(install, cntxt); + decisionMsg.add(clientSD); // setting up the gate + /* + try { + decisionMsg.dump(System.out); + } catch (IOException unae) { + System.out.println("Error dumping " + unae.getMessage()); + } + */ + + } catch (COPSException e) { + System.out.println("Error making Msg" + e.getMessage()); + } + + // ** Send the GateDelete Decision + // ** + try { + decisionMsg.writeData(_sock); + // decisionMsg.writeData(socket_id); + } catch (IOException e) { + System.out.println("Failed to send the decision, reason: " + + e.getMessage()); + } + } + + /** + * Sends a request asking that a new request state be created + * + * @throws COPSPdpException + */ + public void sendOpenNewRequestState() throws COPSPdpException { + /* + * ::= *() [] ::= + * ::= Install Request-State + */ + + // Common Header with the same ClientType as the request (default + // UNSOLICITED) + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + // Decisions + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + // + COPSDecision dec = new COPSDecision(); + dec.setCmdCode(COPSDecision.DEC_INSTALL); + dec.setFlags(COPSDecision.F_REQSTATE); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(clienthandle); + decisionMsg.addDecision(dec, cntxt); + } catch (COPSException e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException( + "Failed to send the open new request state, reason: " + + e.getMessage()); + } + } + + /** + * Sends a message asking for a COPS sync operation + * + * @throws COPSPdpException + */ + public void sendGateInfo() throws COPSPdpException { + /* + * ::= [] [] + */ + + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_SSQ, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + COPSSyncStateMsg msg = new COPSSyncStateMsg(); + try { + msg.add(hdr); + msg.add(clienthandle); + } catch (Exception e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException( + "Failed to send the GateInfo request, reason: " + + e.getMessage()); + } + } + + /** + * Sends a message asking for a COPS sync operation + * + * @throws COPSPdpException + */ + public void sendSyncRequest() throws COPSPdpException { + /* + * ::= [] + * [] + */ + + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_SSQ, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + COPSSyncStateMsg msg = new COPSSyncStateMsg(); + try { + msg.add(hdr); + msg.add(clienthandle); + } catch (Exception e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException( + "Failed to send the sync state request, reason: " + + e.getMessage()); + } + } + // XXX - Temp + public void sendSyncRequestState() throws COPSPdpException { + } + // XXX - Temp + public void sendDeleteRequestState() throws COPSPdpException { + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMPdpReqStateMan.java b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpReqStateMan.java new file mode 100644 index 0000000..6ef939b --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMPdpReqStateMan.java @@ -0,0 +1,461 @@ +/** + @header@ + */ + +package org.pcmm; + +/* +import java.io.*; +import java.util.UUID.*; +*/ +import java.net.Socket; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.pcmm.gates.ITransactionID; +import org.pcmm.gates.impl.PCMMGateReq; +import org.umu.cops.common.COPSDebug; +import org.umu.cops.prpdp.COPSPdpException; +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSPrObjBase; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReportType; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; +/* +import org.pcmm.base.IPCMMBaseObject; +import org.pcmm.gates.IAMID; +import org.pcmm.gates.IGateID; +import org.pcmm.gates.ISubscriberID; +import org.pcmm.gates.IPCError; +import org.pcmm.gates.impl.AMID; +import org.pcmm.gates.impl.GateID; +import org.pcmm.gates.impl.SubscriberID; +import org.pcmm.gates.impl.TransactionID; +import org.pcmm.gates.impl.PCError; +*/ + + + + +/** + * State manager class for provisioning requests, at the PDP side. + */ +public class PCMMPdpReqStateMan { + + /** + * Request State created + */ + public final static short ST_CREATE = 1; + /** + * Request received + */ + public final static short ST_INIT = 2; + /** + * Decisions sent + */ + public final static short ST_DECS = 3; + /** + * Report received + */ + public final static short ST_REPORT = 4; + /** + * Request State finalized + */ + public final static short ST_FINAL = 5; + /** + * New Request State solicited + */ + public final static short ST_NEW = 6; + /** + * Delete Request State solicited + */ + public final static short ST_DEL = 7; + /** + * SYNC request sent + */ + public final static short ST_SYNC = 8; + /** + * SYNC completed + */ + public final static short ST_SYNCALL = 9; + /** + * Close connection received + */ + public final static short ST_CCONN = 10; + /** + * Keep-alive timeout + */ + public final static short ST_NOKA = 11; + /** + * Accounting timeout + */ + public final static short ST_ACCT = 12; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + * Object for performing policy data processing + */ + protected PCMMPdpDataProcess _process; + + /** + * Current state of the request being managed + */ + protected short _status; + + /** COPS message transceiver used to send COPS messages */ + protected PCMMPdpMsgSender _sender; + + /** + * Creates a request state manager + * @param clientType Client-type + * @param clientHandle Client handle + */ + public PCMMPdpReqStateMan(short clientType, String clientHandle) { + // COPS Handle + _handle = new COPSHandle(); + COPSData id = new COPSData(clientHandle); + _handle.setId(id); + // client-type + _clientType = clientType; + + _status = ST_CREATE; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the client-type + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Gets the status of the request + * @return Request state value + */ + public short getStatus() { + return _status; + } + + /** + * Gets the policy data processing object + * @return Policy data processing object + */ + public PCMMPdpDataProcess getDataProcess() { + return _process; + } + + /** + * Sets the policy data processing object + * @param process Policy data processing object + */ + public void setDataProcess(PCMMPdpDataProcess process) { + _process = process; + } + + /** + * Called when COPS sync is completed + * @param repMsg COPS sync message + * @throws COPSPdpException + */ + protected void processSyncComplete(COPSSyncStateMsg repMsg) + throws COPSPdpException { + + _status = ST_SYNCALL; + + // maybe we should notifySyncComplete ... + } + + /** + * Initializes a new request state over a socket + * @param sock Socket to the PEP + * @throws COPSPdpException + */ + protected void initRequestState(Socket sock) + throws COPSPdpException { + // Inits an object for sending COPS messages to the PEP + _sender = new PCMMPdpMsgSender(_clientType, _handle, sock); + + // Initial state + _status = ST_INIT; + } + + + + /** + * Processes a COPS request + * @param msg COPS request received from the PEP + * @throws COPSPdpException + */ + protected void processRequest(COPSReqMsg msg) + throws COPSPdpException { + + COPSHeader hdrmsg = msg.getHeader(); + COPSHandle handlemsg = msg.getClientHandle(); + COPSContext contextmsg = msg.getContext(); + + //** Analyze the request + //** + + /* ::= + * + * + * *() + * [] + * ::= <*( )> + * + * Very important, this is actually being treated like this: + * ::= | + * + + // Named ClientSI + Vector clientSIs = msg.getClientSI(); + Hashtable reqSIs = new Hashtable(40); + String strobjprid = new String(); + for (Enumeration e = clientSIs.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + + COPSPrObjBase obj = new COPSPrObjBase(clientSI.getData().getData()); + switch (obj.getSNum()) + { + case COPSPrObjBase.PR_PRID: + strobjprid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + reqSIs.put(strobjprid, obj.getData().str()); + // COPSDebug.out(getClass().getName(),"PRID: " + strobjprid); + // COPSDebug.out(getClass().getName(),"EPD: " + obj.getData().str()); + break; + default: + break; + } + } + + //** Here we must retrieve a decision depending on + //** the supplied ClientSIs + // reqSIs is a hashtable with the prid and epds + + // ................ + // + Hashtable removeDecs = new Hashtable(); + Hashtable installDecs = new Hashtable(); + _process.setClientData(this, reqSIs); + + removeDecs = _process.getRemovePolicy(this); + installDecs = _process.getInstallPolicy(this); + + //** We create the SOLICITED decision + //** + _sender.sendDecision(removeDecs, installDecs); + _status = ST_DECS; + */ + } + + /** + * Processes a report + * @param msg Report message from the PEP + * @throws COPSPdpException + */ + protected void processReport(COPSReportMsg msg) + throws COPSPdpException { + + //** Analyze the report + //** + + /* + * ::= + * + * + * *() + * [] + * ::= <[] *()> + * ::= *() + * + * Important, is not parsed + */ + + // COPSHeader hdrmsg = msg.getHeader(); + // COPSHandle handlemsg = msg.getClientHandle(); + + // WriteBinaryDump("COPSReportMessage", msg.getData().getData()); + // Report Type + COPSReportType rtypemsg = msg.getReport(); + + // Named ClientSI + Vector clientSIs = msg.getClientSI(); + COPSClientSI myclientSI = (COPSClientSI) msg.getClientSI().elementAt(0); + byte[] data = Arrays.copyOfRange(myclientSI.getData().getData(), 0, myclientSI.getData().getData().length ); + + // PCMMUtils.WriteBinaryDump("COPSReportClientSI", data); + System.out.println("PCMMGateReq Parse Gate Message"); + PCMMGateReq gateMsg = new PCMMGateReq(data); + + Hashtable repSIs = new Hashtable(40); + String strobjprid = new String(); + for (Enumeration e = clientSIs.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + + COPSPrObjBase obj = new COPSPrObjBase(clientSI.getData().getData()); + switch (obj.getSNum()) { + case COPSPrObjBase.PR_PRID: + System.out.println("COPSPrObjBase.PR_PRID"); + strobjprid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + System.out.println("COPSPrObjBase.PR_EPD"); + repSIs.put(strobjprid, obj.getData().str()); + // COPSDebug.out(getClass().getName(),"PRID: " + strobjprid); + // COPSDebug.out(getClass().getName(),"EPD: " + obj.getData().str()); + break; + default: + COPSDebug.err(getClass().getName(),"Object s-num: " + obj.getSNum() + "stype " + obj.getSType()); + COPSDebug.err(getClass().getName(),"PRID: " + strobjprid); + COPSDebug.err(getClass().getName(),"EPD: " + obj.getData().str()); + break; + } + } + + System.out.println("rtypemsg process"); + //** Here we must act in accordance with + //** the report received + if (rtypemsg.isSuccess()) { + System.out.println("rtypemsg success"); + _status = ST_REPORT; + if (_process != null) + _process.successReport(this, gateMsg); + else +{ + if ( gateMsg.getTransactionID().getGateCommandType() == ITransactionID.GateDeleteAck ) { + System.out.println(getClass().getName()+ ": GateDeleteAck "); + System.out.println(getClass().getName()+ ": GateID = " + gateMsg.getGateID().getGateID()); + if (gateMsg.getGateID().getGateID() == PCMMGlobalConfig.getGateID1()) + PCMMGlobalConfig.setGateID1(0); + if (gateMsg.getGateID().getGateID() == PCMMGlobalConfig.getGateID2()) + PCMMGlobalConfig.setGateID2(0); + + } + if ( gateMsg.getTransactionID().getGateCommandType() == ITransactionID.GateSetAck ) { + System.out.println(getClass().getName()+ ": GateSetAck "); + System.out.println(getClass().getName()+ ": GateID = " + gateMsg.getGateID().getGateID()); + if (0 == PCMMGlobalConfig.getGateID1()) + PCMMGlobalConfig.setGateID1(gateMsg.getGateID().getGateID()); + if (0 == PCMMGlobalConfig.getGateID2()) + PCMMGlobalConfig.setGateID2(gateMsg.getGateID().getGateID()); + } + +} + } else if (rtypemsg.isFailure()) { + System.out.println("rtypemsg failure"); + _status = ST_REPORT; + if (_process != null) + _process.failReport(this, gateMsg); +else +{ + System.out.println(getClass().getName()+ ": " + gateMsg.getError().toString()); +} + + } else if (rtypemsg.isAccounting()) { + System.out.println("rtypemsg account"); + _status = ST_ACCT; + if (_process != null) + _process.acctReport(this, gateMsg); + } + System.out.println("Out processReport"); + } + + /** + * Called when connection is closed + * @param error Reason + * @throws COPSPdpException + */ + protected void processClosedConnection(COPSError error) + throws COPSPdpException { + if (_process != null) + _process.notifyClosedConnection(this, error); + + _status = ST_CCONN; + } + + /** + * Called when no keep-alive is received + * @throws COPSPdpException + */ + protected void processNoKAConnection() + throws COPSPdpException { + if (_process != null) + _process.notifyNoKAliveReceived(this); + + _status = ST_NOKA; + } + + /** + * Deletes the request state + * @throws COPSPdpException + */ + protected void finalizeRequestState() + throws COPSPdpException { + _sender.sendDeleteRequestState(); + _status = ST_FINAL; + } + + /** + * Asks for a COPS sync + * @throws COPSPdpException + */ + protected void syncRequestState() + throws COPSPdpException { + _sender.sendSyncRequestState(); + _status = ST_SYNC; + } + + /** + * Opens a new request state + * @throws COPSPdpException + */ + protected void openNewRequestState() + throws COPSPdpException { + _sender.sendOpenNewRequestState(); + _status = ST_NEW; + } + + /** + * Processes a COPS delete message + * @param dMsg COPSDeleteMsg received from the PEP + * @throws COPSPdpException + */ + protected void processDeleteRequestState(COPSDeleteMsg dMsg) + throws COPSPdpException { + if (_process != null) + _process.closeRequestState(this); + + _status = ST_DEL; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMPepAgent.java b/packetcable-driver/src/main/java/org/pcmm/PCMMPepAgent.java new file mode 100644 index 0000000..394bdf1 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMPepAgent.java @@ -0,0 +1,252 @@ +/** + @header@ + */ + +package org.pcmm; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.prpep.COPSPepAgent; +import org.umu.cops.prpep.COPSPepConnection; +import org.umu.cops.prpep.COPSPepException; +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSTransceiver; + +/** + * This is a provisioning COPS PEP. Responsible for making connection to the PDP + * and maintaining it + */ +public class PCMMPepAgent extends COPSPepAgent implements Runnable { + + /** Well-known port for COPS */ + public static final int WELL_KNOWN_CMTS_PORT = 3918; + + /** + * PDP host IP + */ + private ServerSocket serverSocket; + + /** + * PDP host port + */ + private int serverPort; + + /** + * COPS error returned by PDP + */ + private COPSError error; + + /** + * Creates a PEP agent + * + * @param pepID + * PEP-ID + * @param clientType + * Client-type + */ + public PCMMPepAgent(String pepID, short clientType) { + super(pepID, clientType); + serverPort = WELL_KNOWN_CMTS_PORT; + } + + /** + * Creates a PEP agent with a PEP-ID equal to "noname" + * + * @param clientType + * Client-type + */ + public PCMMPepAgent(short clientType) { + super(clientType); + serverPort = WELL_KNOWN_CMTS_PORT; + } + + /** + * Runs the PEP process XXX - not sure of the exception throwing + */ + public void run() { + try { + + COPSDebug.err(getClass().getName(), "Create Server Socket on Port " + + serverPort); + + serverSocket = new ServerSocket(serverPort); + // Loop through for Incoming messages + + // server infinite loop + while (true) { + + // Wait for an incoming connection from a PEP + Socket socket = serverSocket.accept(); + + COPSDebug.err(getClass().getName(), "New connection accepted " + + socket.getInetAddress() + ":" + socket.getPort()); + + processConnection(socket); + /** + * XXX - processConnection handles the open request from PEP And + * a thread is created for conn = new + * COPSPepConnection(_clientType, socket); the main processing + * loop for PEP + */ + + } + } catch (IOException e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } catch (COPSException e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } catch (COPSPepException e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } + } + + /** + * Establish connection to PDP's IP address + * + * ::= [] [] + * [] + * + * Not support [], [], [] + * + * ::= [] + * [] + * + * Not send [] + * + * ::= [] [] + * + * Not send [], [] + * + * @throws UnknownHostException + * @throws IOException + * @throws COPSException + * @throws COPSPepException + * + */ + private COPSPepConnection processConnection(Socket socket) + throws UnknownHostException, IOException, COPSException, + COPSPepException { + // Build OPN + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_OPN, getClientType()); + + COPSPepId pepId = new COPSPepId(); + COPSData d = new COPSData(getPepID()); + pepId.setData(d); + + COPSClientOpenMsg msg = new COPSClientOpenMsg(); + msg.add(hdr); + msg.add(pepId); + + // Create Socket and send OPN + /* + * InetAddress addr = InetAddress.getByName(psHost); Socket socket = new + * Socket(addr,psPort); + */ + COPSDebug.err(getClass().getName(), "Send COPSClientOpenMsg to PDP"); + msg.writeData(socket); + + // Receive the response + COPSDebug.err(getClass().getName(), "Receive the resposne from PDP"); + COPSMsg recvmsg = COPSTransceiver.receiveMsg(socket); + + if (recvmsg.getHeader().isAClientAccept()) { + COPSDebug.err(getClass().getName(), "isAClientAccept from PDP"); + COPSClientAcceptMsg cMsg = (COPSClientAcceptMsg) recvmsg; + + // Support + if (cMsg.getIntegrity() != null) { + throw new COPSPepException("Unsupported object (Integrity)"); + } + + // Mandatory KATimer + COPSKATimer kt = cMsg.getKATimer(); + if (kt == null) + throw new COPSPepException( + "Mandatory COPS object missing (KA Timer)"); + short _kaTimeVal = kt.getTimerVal(); + + // ACTimer + COPSAcctTimer at = cMsg.getAcctTimer(); + short _acctTimer = 0; + if (at != null) + _acctTimer = at.getTimerVal(); + + // Create the connection manager + COPSPepConnection conn = new COPSPepConnection(getClientType(), + socket); + conn.setKaTimer(_kaTimeVal); + conn.setAcctTimer(_acctTimer); + COPSDebug.err(getClass().getName(), "Thread(conn).start"); + new Thread(conn).start(); + + return conn; + } else if (recvmsg.getHeader().isAClientClose()) { + COPSDebug.err(getClass().getName(), "isAClientClose from PDP"); + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) recvmsg; + error = cMsg.getError(); + socket.close(); + return null; + } else { // messages of other types are not expected + throw new COPSPepException( + "Message not expected. Closing connection for " + + socket.toString()); + } + } + + /** + * Gets the COPS error returned by the PDP + * + * @return COPSError returned by PDP + */ + public COPSError getConnectionError() { + return error; + } + + public void setConnectionError(COPSError _error) { + this.error = _error; + } + + /** + * @return the serverSocket + */ + public ServerSocket getServerSocket() { + return serverSocket; + } + + /** + * @param serverSocket + * the serverSocket to set + */ + public void setServerSocket(ServerSocket serverSocket) { + this.serverSocket = serverSocket; + } + + /** + * @return the serverPort + */ + public int getServerPort() { + return serverPort; + } + + /** + * @param serverPort + * the serverPort to set + */ + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/PCMMProperties.java b/packetcable-driver/src/main/java/org/pcmm/PCMMProperties.java new file mode 100644 index 0000000..62e4678 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/PCMMProperties.java @@ -0,0 +1,60 @@ +package org.pcmm; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Loads the PCMM Properties file. + * + */ +public class PCMMProperties implements PCMMConstants { + + private static Properties properties; + private static Logger logger = LoggerFactory.getLogger(PCMMProperties.class); + + static { + try { + InputStream in = PCMMProperties.class.getClassLoader().getResourceAsStream("pcmm.properties"); + properties = new Properties(); + properties.load(in); + in.close(); + } catch (IOException ie) { + logger.error(ie.getMessage()); + } + } + + protected static String get(String key) { + return properties.getProperty(key); + } + + @SuppressWarnings("unchecked") + public static T get(String key, Class type, Object _default) { + String prop = get(key); + if (prop != null && !prop.isEmpty()) { + if (Boolean.class.isAssignableFrom(type)) + return (T) Boolean.valueOf(prop); + else if (Integer.class.isAssignableFrom(type)) + return (T) Integer.valueOf(prop); + else if (Short.class.isAssignableFrom(type)) + return (T) Short.valueOf(prop); + if (Float.class.isAssignableFrom(type)) + return (T) Float.valueOf(prop); + if (Long.class.isAssignableFrom(type)) + return (T) Long.valueOf(prop); + if (Double.class.isAssignableFrom(type)) + return (T) Double.valueOf(prop); + else if (String.class.isAssignableFrom(type)) + return (T) prop; + } + return (T) _default; + } + + public static T get(String key, Class type) { + return get(key, type, null); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/base/IAdapter.java b/packetcable-driver/src/main/java/org/pcmm/base/IAdapter.java new file mode 100644 index 0000000..42cdd47 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/base/IAdapter.java @@ -0,0 +1,15 @@ +/** + * + */ +package org.pcmm.base; + +/** + * Adapter interface + * + */ +public interface IAdapter { + + Object adapt(Object object, Class clazz); + + Type adapt(Object object); +} diff --git a/packetcable-driver/src/main/java/org/pcmm/base/IPCMMBaseObject.java b/packetcable-driver/src/main/java/org/pcmm/base/IPCMMBaseObject.java new file mode 100644 index 0000000..2114004 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/base/IPCMMBaseObject.java @@ -0,0 +1,80 @@ +/** + @header@ + */ + +package org.pcmm.base; + +import java.io.IOException; +import java.net.Socket; + +import org.umu.cops.stack.COPSData; + +/** + * Base interface for all PCMM objects, it define the {@code S-Type}, + * {@code S-Num} and the data length + * + */ +public interface IPCMMBaseObject { + + /** + * sets the S-Type + * + * @param stype + */ + void setSType(byte stype); + + /** + * + * @return S-Type + */ + byte getSType(); + + /** + * sets the S-Num + * + * @param snum + * S-Num + */ + void setSNum(byte snum); + + /** + * gets the S-Num + * + * @return S-Num + */ + byte getSNum(); + + /** + * sets the length; + * + * @param len + */ + void setLength(short len); + + /** + * gets the length; + * + * @return length + */ + short getLength(); + + /** + * sets the COPS data + * + * @param data + * COPS data + */ + void setData(COPSData data); + + /** + * gets the COPS data + * + * @return COPS data + */ + COPSData getData(); + + void writeData(Socket id) throws IOException; + + byte[] getAsBinaryArray(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/base/impl/PCMMBaseObject.java b/packetcable-driver/src/main/java/org/pcmm/base/impl/PCMMBaseObject.java new file mode 100644 index 0000000..79e26de --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/base/impl/PCMMBaseObject.java @@ -0,0 +1,244 @@ +/** + * + */ +package org.pcmm.base.impl; + +import java.io.IOException; +import java.net.Socket; +import java.util.Arrays; + +import org.pcmm.base.IPCMMBaseObject; +import org.umu.cops.stack.COPSData; + +/** + * + * Implementation of the base class {@link IPCMMBaseObject} + * + */ +public class PCMMBaseObject /* extends COPSPrObjBase */implements + IPCMMBaseObject { + + private byte sType; + private byte sNum; + private short len; + private COPSData copsData; + private COPSData pad; + protected final short offset = (short) 4; + + public PCMMBaseObject(byte[] data) { + parse(data); + } + + public PCMMBaseObject(short len, byte sType, byte sNum) { + this.len = (len); + this.sType = (sType); + this.sNum = (sNum); + byte[] array = new byte[len - offset]; + Arrays.fill(array, (byte) 0); + setData(new COPSData(array, 0, array.length)); + } + + protected COPSData getPadding(int len) { + byte[] padBuf = new byte[len]; + Arrays.fill(padBuf, (byte) 0); + COPSData d = new COPSData(padBuf, 0, len); + return d; + } + + /** + * Add head padding to the specified byte array filled with zeros + * + * @param off + * offset + * @param array + * input array + * @return byte array + */ + protected byte[] headPadding(int off, byte[] array) { + byte[] returnArray = new byte[array.length + off]; + Arrays.fill(returnArray, (byte) 0); + System.arraycopy(array, 0, returnArray, off, array.length); + return returnArray; + } + + protected void parse(byte[] data) { + if (data == null || data.length == 0) + throw new IllegalArgumentException("data could not be null"); + len = 0; + len |= ((short) data[0]) << 8; + len |= ((short) data[1]) & 0xFF; + sNum = data[2]; + sType = data[3]; + copsData = new COPSData(data, offset, data.length - offset); + } + + protected void setShort(short value, short startPos) { + byte[] data = getData().getData(); + data[startPos] = (byte) (value >> 8); + data[startPos + 1] = (byte) value; + setData(new COPSData(data, 0, data.length)); + } + + protected short getShort(short startPos) { + byte[] data = getData().getData(); + short retVal = 0; + retVal |= ((short) data[startPos]) << 8; + retVal |= ((short) data[startPos + 1]) & 0xFF; + return retVal; + } + + protected void setInt(int value, short startPos) { + byte[] data = getData().getData(); + data[startPos] = (byte) (value >> 24); + data[startPos + 1] = (byte) (value >> 16); + data[startPos + 2] = (byte) (value >> 8); + data[startPos + 3] = (byte) value; + setData(new COPSData(data, 0, data.length)); + } + + protected int getInt(short startPos) { + byte[] data = getData().getData(); + int retVal = 0; + retVal |= ((short) data[startPos]) << 24; + retVal |= ((short) data[startPos + 1]) << 16; + retVal |= ((short) data[startPos + 2]) << 8; + retVal |= ((short) data[startPos + 3]) & 0xFF; + return retVal; + } + + protected void setBytes(byte[] value, short startPos) { + byte[] data = getData().getData(); + for (byte b : value) + data[startPos++] = b; + setData(new COPSData(data, 0, data.length)); + } + + protected byte[] getBytes(short startPos, short size) { + return Arrays.copyOfRange(getData().getData(), startPos, startPos + + size); + } + + protected void setByte(byte value, short startPos) { + setBytes(new byte[] { value }, startPos); + } + + protected byte getByte(short startPos) { + return getBytes(startPos, (short) 1)[0]; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#setSType(byte) + */ + @Override + public void setSType(byte stype) { + this.sType = stype; + + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#getSType() + */ + @Override + public byte getSType() { + return sType; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#setSNum(byte) + */ + @Override + public void setSNum(byte snum) { + this.sNum = snum; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#getSNum() + */ + @Override + public byte getSNum() { + return sNum; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#setLength(short) + */ + @Override + public void setLength(short len) { + this.len = len; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#getLength() + */ + @Override + public short getLength() { + return (short) (len + (pad != null ? pad.length() : 0)); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#setData(org.umu.cops.stack.COPSData) + */ + @Override + public void setData(COPSData data) { + this.copsData = data; + if (data.length() % offset != 0) { + int padLen = offset - (data.length() % offset); + pad = getPadding(padLen); + } + len = (short) (data.length() + offset); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#getData() + */ + @Override + public COPSData getData() { + return copsData; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#writeData(java.net.Socket) + */ + public void writeData(Socket id) throws IOException { + byte[] data = getAsBinaryArray(); + id.getOutputStream().write(data, 0, data.length); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.base.IPCMMBaseObject#getAsBinaryArray() + */ + @Override + public byte[] getAsBinaryArray() { + byte[] array = new byte[getLength()]; + array[0] = (byte) (len >> 8); + array[1] = (byte) len; + array[2] = sNum; + array[3] = sType; + System.arraycopy(getData().getData(), 0, array, offset, getData() + .length()); + if (pad != null) + System.arraycopy(pad.getData(), 0, array, offset + + getData().length(), pad.length()); + return array; + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/concurrent/IWorker.java b/packetcable-driver/src/main/java/org/pcmm/concurrent/IWorker.java new file mode 100644 index 0000000..1a89605 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/concurrent/IWorker.java @@ -0,0 +1,28 @@ +package org.pcmm.concurrent; + +import java.util.concurrent.Callable; +/** + * + */ +public interface IWorker extends Runnable { + + /** + * defines the task to be performed by this worker + * + * @param c + */ + void task(Callable c); + + /** + * defines wait time before start working on the task + * + * @param t + */ + void shouldWait(int t); + + /** + * ends the current working task. + */ + void done(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/concurrent/IWorkerPool.java b/packetcable-driver/src/main/java/org/pcmm/concurrent/IWorkerPool.java new file mode 100644 index 0000000..e97cc21 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/concurrent/IWorkerPool.java @@ -0,0 +1,54 @@ +/** + * + */ +package org.pcmm.concurrent; + +import org.pcmm.base.IAdapter; + +/** + * + */ +public interface IWorkerPool extends IAdapter { + // handles 32 workers + static int DEFAULT_MAX_WORKERS = 32; + + /** + * schedules a worker for beginning its task after t milliseconds. + * + * @param worker + * : the worker + * @param t + * : time to wait + * @return the id of the worker (PID) to be used for killing the worker if + * needed + */ + int schedule(IWorker worker, int t); + + /** + * schedules a worker for immediate execution. + * + * @param worker + * : the worker + * @return the id of the worker (PID) to be used for killing the worker if + * needed + */ + int schedule(IWorker worker); + + /** + * kills the worker with the specified pid + * + * @param pid + */ + void sendKillSignal(int pid); + + /** + * sends a terminate signal for all active workers and recycles the pool. + */ + void killAll(); + + /** + * cleans up the pool from finished tasks + */ + void recycle(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/concurrent/impl/Worker.java b/packetcable-driver/src/main/java/org/pcmm/concurrent/impl/Worker.java new file mode 100644 index 0000000..1080692 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/concurrent/impl/Worker.java @@ -0,0 +1,79 @@ +/** + * + */ +package org.pcmm.concurrent.impl; + +import java.util.concurrent.Callable; + +import org.pcmm.concurrent.IWorker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class Worker implements IWorker { + + private int waitTimer; + + private Callable task; + private Logger logger = LoggerFactory.getLogger(IWorker.class); + + public Worker() { + + } + + public Worker(Callable task) { + this.task = task; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + try { + if (waitTimer > 0) + Thread.sleep(waitTimer); + task.call(); + } catch (Throwable e) { + logger.error(e.getMessage()); + } + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.threading.IWorker#task(java.util.concurrent.Callable) + */ + @Override + public void task(Callable c) { + logger.debug("Task added " + c); + this.task = c; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.threading.IWorker#shouldWait(int) + */ + @Override + public void shouldWait(int t) { + logger.debug("Worker will start after :" + t + " ms"); + waitTimer = t; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.threading.IWorker#done() + */ + @Override + public void done() { + logger.debug("worker finished tasks"); + + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/concurrent/impl/WorkerPool.java b/packetcable-driver/src/main/java/org/pcmm/concurrent/impl/WorkerPool.java new file mode 100644 index 0000000..b6fb429 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/concurrent/impl/WorkerPool.java @@ -0,0 +1,158 @@ +package org.pcmm.concurrent.impl; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.pcmm.concurrent.IWorker; +import org.pcmm.concurrent.IWorkerPool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Pool to manage PCMM workers + */ +public class WorkerPool implements IWorkerPool { + + /** + * + */ + private Map> workersMap; + + private Logger logger = LoggerFactory.getLogger(IWorkerPool.class); + private ExecutorService executor; + + public WorkerPool() { + this(DEFAULT_MAX_WORKERS); + } + + public WorkerPool(int size) { + logger.info("Pool size :" + size); + workersMap = new HashMap>(); + executor = Executors.newFixedThreadPool(size); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.threading.IWorkerPool#schedule(org.pcmm.threading.IWorker, + * int) + */ + @Override + public int schedule(IWorker worker, int t) { + if (worker == null) + return -1; + logger.debug("woker[" + worker + "] added, starts in " + t + " ms"); + WeakReference workerRef = new WeakReference(worker); + int ref = workerRef.hashCode(); + workersMap.put(ref, workerRef); + worker.shouldWait(t); + executor.execute(worker); + return ref; + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.concurrent.IWorkerPool#schedule(org.pcmm.concurrent.IWorker) + */ + @Override + public int schedule(IWorker worker) { + return schedule(worker, 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.concurrent.IWorkerPool#sendKillSignal(int) + */ + @Override + public void sendKillSignal(int pid) { + if (workersMap.size() > 0) { + WeakReference weakRef = workersMap.get(pid); + if (weakRef != null) { + IWorker ref = weakRef.get(); + if (ref != null) + ref.done(); + if (!weakRef.isEnqueued()) { + weakRef.clear(); + weakRef.enqueue(); + } + } + } + + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.threading.IWorkerPool#killAll() + */ + @Override + public void killAll() { + for (WeakReference weakRef : workersMap.values()) { + IWorker ref = weakRef.get(); + if (ref != null) + ref.done(); + if (!weakRef.isEnqueued()) { + weakRef.clear(); + weakRef.enqueue(); + } + } + recycle(); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.threading.IWorkerPool#recycle() + */ + @Override + public void recycle() { + for (Iterator pids = workersMap.keySet().iterator(); pids.hasNext();) { + WeakReference weakRef = workersMap.get(pids.next()); + IWorker ref = weakRef.get(); + if (ref == null) { + if (!weakRef.isEnqueued()) { + weakRef.clear(); + weakRef.enqueue(); + } + workersMap.remove(weakRef); + } + } + + } + + @Override + public Object adapt(Object object, Class clazz) { + if (clazz.isAssignableFrom(object.getClass())) + return object; + return null; + } + + @Override + public IWorker adapt(Object object) { + IWorker worker = (IWorker) adapt(object, IWorker.class); + if (worker == null) { + if (object instanceof Callable) + worker = new Worker((Callable) object); + else if (object instanceof Runnable) { + final Runnable runner = (Runnable) object; + worker = new Worker(new Callable() { + @Override + public Object call() throws Exception { + ((Runnable) runner).run(); + return null; + } + }); + } + } + return worker; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IAMID.java b/packetcable-driver/src/main/java/org/pcmm/gates/IAMID.java new file mode 100644 index 0000000..71e8116 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IAMID.java @@ -0,0 +1,51 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + +import org.pcmm.base.IPCMMBaseObject; + +/** + *

+ * The AMID consists of two fields: the Application Manager Tag and Application + * Type. Each Application Manager is pre-provisioned with an Application Manager + * Tag that is unique within the universe of a single service provider. The + * Application Manager may also be pre-provisioned with a set of Application + * Type values that can be used to identify the particular application that a + * gate is associated with. The Application Manager includes the AMID in all + * messages that it issues to the Policy Server. The Policy Server transparently + * passes this information to the CMTS via Gate Control messages. The CMTS MUST + * return the AMID associated with the Gate to the Policy Server. The Policy + * Server uses this information to associate Gate messages with a particular + * Application Manager and Application Type. + *

+ *

+ * The Application Manager Tag MUST be a globally unique value assigned to the + * Application Manager by the service provider. The Application Manager MUST use + * the assigned Application Manager Tag in all its interactions with Policy + * Servers. Note that since the Application Manager may be operated by a third + * party, and a single Application Manager could interact with multiple service + * provider operators, a single physical Application Manager may be provisioned + * with multiple Application Manager Tags, and multiple Application Type sets + * (one for each configured Application Manager Tag). + *

+ * + * + */ +public interface IAMID extends IPCMMBaseObject { + + static final short LENGTH = 8; + static final byte SNUM = 2; + static final byte STYPE = 1; + + void setApplicationType(short type); + + short getApplicationType(); + + void setApplicationMgrTag(short type); + + short getApplicationMgrTag(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IClassifier.java b/packetcable-driver/src/main/java/org/pcmm/gates/IClassifier.java new file mode 100644 index 0000000..6aea0ae --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IClassifier.java @@ -0,0 +1,128 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + +import java.net.InetAddress; + +import org.pcmm.base.IPCMMBaseObject; + +/** + * + * + * + */ +public interface IClassifier extends IPCMMBaseObject { + + static final short LENGTH = 24; + static final byte SNUM = 6; + static final byte STYPE = 1; + + static enum Protocol { + /*ICMP((short) 1), IGMP((short) 2), */ + NONE((short)0), TCP((short) 6), UDP((short) 17); + + Protocol(short v) { + this.value = v; + } + + public static Protocol valueOf(short v) { + switch (v) { + case 0: + return NONE; + /* + case 1: + return ICMP; + case 2: + return IGMP; + */ + case 6: + return TCP; + default: + return UDP; + } + } + private short value; + + public short getValue() { + return value; + } + } + + /** + * IP Destination Address or IPv6 Destination Address is the termination + * point for the IP flow + * + * @return destination IP address. + */ + InetAddress getDestinationIPAddress(); + + void setDestinationIPAddress(InetAddress address); + + short getDestinationPort(); + + void setDestinationPort(short p); + + /** + * Source IP, IP Source Address, or IPv6 Source Address (in the case of + * Extended Classifier or IPv6 Classifier) is the IP address (as seen at the + * CMTS) of the originator of the IP flow. + * + * @return source IP address. + */ + InetAddress getSourceIPAddress(); + + void setSourceIPAddress(InetAddress a); + + short getSourcePort(); + + void setSourcePort(short p); + + /** + * Protocol field, in a legacy Classifier or Extended Classifier, identifies + * the type of protocol (e.g., IP, ICMP, etc.). The Next Header Type field + * serves a similar function in the IPv6 Classifier. + * + * @return the protocol. + */ + Protocol getProtocol(); + + /** + * @see protocols + * @param p + */ + void setProtocol(Protocol p); + + /** + * Priority may be used to distinguish between multiple classifiers that + * match a particular packet. This is typically set to a default value since + * classifiers are generally intended to be unique. + * + * @return priority. + */ + byte getPriority(); + + /** + * sets the priority; + * + * @param p + * priority + */ + void setPriority(byte p); + + byte getDSCPTOS(); + + void setDSCPTOS(byte v); + + byte getDSCPTOSMask(); + + void setDSCPTOSMask(byte v); + + // DSCP/TOS Field + //  + // DSCP/TOS Mask + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IExtendedClassifier.java b/packetcable-driver/src/main/java/org/pcmm/gates/IExtendedClassifier.java new file mode 100644 index 0000000..635bf25 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IExtendedClassifier.java @@ -0,0 +1,69 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + +import java.net.InetAddress; + +public interface IExtendedClassifier extends IClassifier { + + static final short LENGTH = 40; + static final byte SNUM = 6; + static final byte STYPE = 2; + + void setIPSourceMask(InetAddress a); + + void setIPDestinationMask(InetAddress m); + + void setSourcePortStart(short p); + + void setSourcePortEnd(short p); + + void setDestinationPortStart(short p); + + void setDestinationPortEnd(short p); + + void setClassifierID(short p); + + /** + *
+     * 0x00 Inactive
+     * 0x01 Active
+     * 
+ * + * @param s + */ + void setActivationState(byte s); + + /** + *
+     * 0x00 Add classifier
+     * 0x01 Replace classifier
+     * 0x02 Delete classifier
+     * 0x03 No change
+     * 
+ * + * @param a + */ + void setAction(byte a); + + InetAddress getIPSourceMask(); + + InetAddress getIPDestinationMask(); + + short getSourcePortStart(); + + short getSourcePortEnd(); + + short getDestinationPortStart(); + + short getDestinationPortEnd(); + + short getClassifierID(); + + byte getActivationState(); + + byte getAction(); +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IGateID.java b/packetcable-driver/src/main/java/org/pcmm/gates/IGateID.java new file mode 100644 index 0000000..d6d9582 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IGateID.java @@ -0,0 +1,19 @@ +/** + @header@ + */ +package org.pcmm.gates; + +import org.pcmm.base.IPCMMBaseObject; + +/** + * + */ +public interface IGateID extends IPCMMBaseObject { + static final short LENGTH = 8; + static final byte SNUM = 4; + static final byte STYPE = 1; + + void setGateID(int gateID); + + int getGateID(); +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IGateSpec.java b/packetcable-driver/src/main/java/org/pcmm/gates/IGateSpec.java new file mode 100644 index 0000000..10f4500 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IGateSpec.java @@ -0,0 +1,246 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + +import org.pcmm.base.IPCMMBaseObject; + +/** + *

+ * The GateSpec describes some high-level attributes of the Gate, and contains + * information regarding the treatment of other objects specified in the Gate + * message. + *

+ * + * + * + * + */ +public interface IGateSpec extends IPCMMBaseObject { + + static final byte SNUM = 5; + static final byte STYPE = 1; + static final short LENGTH = 16; + + /** + *

+ * Direction indicates whether the Gate is for an upstream or downstream + * flow. Depending on this direction, the CMTS MUST reserve and activate the + * DOCSIS flows accordingly. For Multicast Gates the CMTS needs to only + * support flows or gates in the downstream direction. + *

+ * + * + */ + public enum Direction { + + UPSTREAM((byte) 1), DOWNSTREAM((byte) 0); + + private Direction(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } + + @Override + public String toString() { + switch (value) { + case 1: + return "Upstream"; + default: + return "Downstream"; + } + } + + private byte value; + + public static Direction valueOf(byte v) { + switch (v) { + case 0: + return Direction.DOWNSTREAM; + case 1: + return Direction.UPSTREAM; + default: + throw new IllegalArgumentException("not supported value"); + } + } + + }; + + /** + * + */ + public enum DSCPTOS { + + ENABLE((byte) 1), OVERRIDE((byte) 0); + + private DSCPTOS(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } + + @Override + public String toString() { + switch (value) { + case 1: + return "Enable"; + default: + return "Override"; + } + } + + public static DSCPTOS valueOf(byte v) { + switch (v) { + case 0: + return DSCPTOS.OVERRIDE; + case 1: + return DSCPTOS.ENABLE; + default: + throw new IllegalArgumentException("not supported value"); + } + } + + private byte value; + + }; + + /** + *

+ * provides a way for the Application Manager and the Policy Server to group + * Gates into different classes with different authorization + * characteristics. For example, one could use the SessionClassID to + * represent some prioritization or preemption scheme that would allow + * either the Policy Server or the CMTS to preempt a pre-authorized Gate in + * favor of allowing a new Gate with a higher priority to be authorized. + *

+ * + * @return session class ID; + */ + ISessionClassID getSessionClassID(); + + /** + *

+ * sets the session class ID; + *

+ *

+ * SessionClassID is a 1-byte unsigned integer value which identifies the + * proper admission control policy or parameters to be applied for this + * Gate. The SessionClassID is a bit field, defined as follows: Bit 0-2: + * Priority, a number from 0 to 7, where 0 is low priority and 7 is high. + * Bit 3: Preemption, set to enable preemption of bandwidth allocated to + * lower priority sessions if necessary (if supported). Bit 4-7: + * Configurable, default to 0 + *

+ */ + void setSessionClassID(ISessionClassID id); + + /** + * + * @return direction. + */ + Direction getDirection(); + + /** + * sets the direction + * + * @param direction + * Direction + */ + void setDirection(Direction direction); + + /** + * Authorized Timer limits the amount of time the authorization must remain + * valid before it is reserved + * + * @return time in ms; + */ + short getTimerT1(); + + /** + * sets the authorized timer + * + * @param authTimer + * : authorized timer + */ + void setTimerT1(short authTimer); + + /** + * Reserved Timer limits the amount of time the reservation must remain + * valid before the resources are committed + * + * @return time in ms; + */ + short getTimerT2(); + + /** + * sets the reserved timer. + * + * @param timer + */ + void setTimerT2(short timer); + + /** + * Committed Timer limits the amount of time a committed service flow may + * remain idle. + * + * @return time in ms; + */ + short getTimerT3(); + + /** + * sets the committed timer. + * + * @param t + * timer + */ + void setTimerT3(short t); + + /** + * Committed Recovery Timer limits the amount of time that a committed + * service flow can remain without a subsequent refresh message from the + * PS/AM once the PS/AM has been notified of inactivity + * + * @return time in ms; + */ + short getTimerT4(); + + /** + * sets the Committed Recovery Timer. + * + * @param t + * timer + */ + void setTimerT4(short t); + + /** + * + * @param dscpTos + */ + void setDSCP_TOSOverwrite(DSCPTOS dscpTos); + + /** + * + * @return DSCP/TOS + */ + DSCPTOS getDSCP_TOSOverwrite(); + + /** + * + * @return + */ + byte getDSCP_TOSMask(); + + /** + * + * @param dscp_tos_mask + */ + void setDSCP_TOSMask(byte dscp_tos_mask); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IIPv6Classifier.java b/packetcable-driver/src/main/java/org/pcmm/gates/IIPv6Classifier.java new file mode 100644 index 0000000..a9d689f --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IIPv6Classifier.java @@ -0,0 +1,31 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + +public interface IIPv6Classifier extends IExtendedClassifier { + static final short LENGTH = 64; + static final byte SNUM = 6; + static final byte STYPE = 3; + + // Tc-low + // Tc-high + // Tc-mask + // Flow Label + // Next Header Type + // Source Prefix Length + // Destination Prefix Length + // IPv6 Source Address + // IPv6 Destination Address + // Source Port Start + // Source Port End + // Destination Port Start + // Destination Port End + // ClassifierID + // Priority + // Activation State + // Action + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IPCMMError.java b/packetcable-driver/src/main/java/org/pcmm/gates/IPCMMError.java new file mode 100644 index 0000000..bd0b47a --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IPCMMError.java @@ -0,0 +1,94 @@ +/** + @header@ + */ +package org.pcmm.gates; + +import org.pcmm.base.IPCMMBaseObject; + +/** + * + */ +public interface IPCMMError extends IPCMMBaseObject { + static final short LENGTH = 8; + static final byte SNUM = 14; + static final byte STYPE = 1; + final String[] errors = { "Insufficient Resources", "Unknown GateID", + "Missing Required Object", "Invalid Object", + "Volume Based Usage Limit Exceeded", + "Time Based Usage Limit Exceeded", "Session Class Limit Exceeded", + "Undefined Service Class Name", "Incompatible Envelope", + "Invalid SubscriberID", "Unauthorized AMID", + "Number of Classifiers Not Supported", "Policy Exception", + "Invalid Field Value in Object", "Transport Error", + "Unknown Gate Command", "DOCSIS 1.0 CM", + "Number of SIDs exceeded in CM", "Number of SIDs exceeded in CMTS", + "Unauthorized PSID", "No State for PDP", "Unsupported Synch Type", + "State Data Incomplete", "Upstream Drop Unsupported", + "Multicast Gate Error", "Multicast Volume Limit Unsupported", + "Uncommitted Multicast Not Supported", + "Multicast Gate Modification Not Supported", + "Upstream Multicast Not Supported", + "Multicast GateSpec incompatibility", "Multicast QoS Error", + "Multicast Downstream Resequencing mismatch", + "Other, Unspecified Error" }; + + static enum Description { + ERROR_01((short) 1, errors[0]), ERROR_02((short) 2, errors[1]), ERROR_06( + (short) 6, errors[2]), ERROR_07((short) 7, errors[3]), ERROR_08( + (short) 8, errors[4]), ERROR_09((short) 9, errors[5]), ERROR_10( + (short) 10, errors[6]), ERROR_11((short) 11, errors[7]), ERROR_12( + (short) 12, errors[8]), ERROR_13((short) 13, errors[9]), ERROR_14( + (short) 14, errors[10]), ERROR_15((short) 15, errors[11]), ERROR_16( + (short) 16, errors[12]), ERROR_17((short) 17, errors[13]), ERROR_18( + (short) 18, errors[14]), ERROR_19((short) 19, errors[15]), ERROR_20( + (short) 20, errors[16]), ERROR_21((short) 21, errors[17]), ERROR_22( + (short) 22, errors[18]), ERROR_23((short) 23, errors[19]), ERROR_24( + (short) 24, errors[20]), ERROR_25((short) 25, errors[21]), ERROR_26( + (short) 26, errors[22]), ERROR_27((short) 27, errors[23]), ERROR_28( + (short) 28, errors[24]), ERROR_29((short) 29, errors[25]), ERROR_30( + (short) 30, errors[26]), ERROR_31((short) 31, errors[27]), ERROR_32( + (short) 32, errors[28]), ERROR_33((short) 33, errors[29]), ERROR_34( + (short) 34, errors[30]), ERROR_35((short) 35, errors[31]), ERROR_127( + (short) 127, errors[28]); + + private final short code; + private final String description; + + private Description(short code, String description) { + this.code = code; + this.description = description; + } + + public String getDescription() { + return description; + } + + public short getCode() { + return code; + } + + public static String valueOf(short errCode) { + switch (errCode) { + case 1: + case 2: + return errors[errCode - 1]; + case 127: + return errors[32]; + default: + if (errCode > 35 || errCode < 1) + throw new IllegalArgumentException("unrecongnized error code : " + errCode); + return errors[errCode - 4]; + } + } + } + + void setErrorCode(short ErrorCode); + + short getErrorCode(); + + void setErrorSubcode(short ErrorSubcode); + + short getErrorSubcode(); + + String getDescription(); +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/IPCMMGate.java b/packetcable-driver/src/main/java/org/pcmm/gates/IPCMMGate.java new file mode 100644 index 0000000..ada6a51 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/IPCMMGate.java @@ -0,0 +1,145 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + + +/** + *

+ * A PacketCable Multimedia Gate is a logical representation of a policy + * decision that has been installed on the CMTS. A Gate is used to control + * access by a single IP flow to enhanced QoS Services provided by a DOCSIS + * cable network. Gates are unidirectional; a single Gate controls access to a + * flow in either the upstream or the downstream direction, but not both. For a + * bi-directional IP session, two Gates are required, one for upstream and one + * for downstream, each identified by a unique GateID. It is important to + * recognize that this is a fundamental difference from PacketCable 1.x, in + * which a single GateID may reference both an upstream and a downstream Gate. + *

+ *

+ * In PacketCable Multimedia, each Gate has a separate GateID. The Gate defines + *

+ *

+ * + *

+ * + * + */ +public interface IPCMMGate { + + + /** + * + * @return whether this gate is multicast or unicast. + */ + boolean isMulticast(); + + /** + * GateID is the handle for the Gate. + * + */ + void setGateID(IGateID gateid); + + /** + * AMID is the handle that identifies the Application Manager and + * Application Type + * + */ + void setAMID(IAMID iamid); + + /** + * SubscriberID uniquely identifies the Client for which the policy is being + * set. + * + */ + void setSubscriberID(ISubscriberID subscriberID); + + /** + * (i.e., QoS limits, timers, etc.). + * + */ + void setGateSpec(IGateSpec gateSpec); + + /** + * Classifier describes the IP flow(s) that will be mapped to the DOCSIS + * Service Flow. + * + */ + void setClassifier(IClassifier classifier); + + /** + * Traffic Profile describes the QoS attributes of the Service Flow used to + * support the IP flow. + */ + void setTrafficProfile(ITrafficProfile profile); + + void setTransactionID(ITransactionID transactionID); + + void setError(IPCMMError error); + + ITransactionID getTransactionID(); + + /** + * GateID is the handle for the Gate. + * + * @return gateID + */ + IGateID getGateID(); + + /** + * AMID is the handle that identifies the Application Manager and + * Application Type + * + * @return AMID handle. + */ + IAMID getAMID(); + + /** + * SubscriberID uniquely identifies the Client for which the policy is being + * set. + * + * @return unique subscriber ID. + */ + ISubscriberID getSubscriberID(); + + /** + * (i.e., QoS limits, timers, etc.). + * + * @return gateSpec object. + */ + IGateSpec getGateSpec(); + + /** + * Classifier describes the IP flow(s) that will be mapped to the DOCSIS + * Service Flow. + * + * @return Classifier object. + */ + IClassifier getClassifier(); + + /** + * Traffic Profile describes the QoS attributes of the Service Flow used to + * support the IP flow. + */ + ITrafficProfile getTrafficProfile(); + + /** + * The PacketCable Error object contains information on the type of error that has occurred. + */ + IPCMMError getError(); + + + /** + * + * @return cops data + */ + byte[] getData(); + // Event Generation Info (optional) + // Time-Based Usage Limit (optional) + // Volume-Based Usage Limit (optional) + // Opaque Data (optional) + // UserID (optional) + // SharedResourceID (optional) +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/ISessionClassID.java b/packetcable-driver/src/main/java/org/pcmm/gates/ISessionClassID.java new file mode 100644 index 0000000..11ca7f2 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/ISessionClassID.java @@ -0,0 +1,48 @@ +/** + @header@ + */ +package org.pcmm.gates; + +/** + * + */ +public interface ISessionClassID { + + /** + * gets the priority bits + * + * @return O-7 priority value + */ + byte getPriority(); + + /** + * sets the priority value (0-7) + * + * @param value + * priority + */ + void setPriority(byte value); + + /** + * gets the preemption value; + * + * @return peemption + */ + byte getPreemption(); + + /** + * * sets the preemption + * + * @param value + * preemption + */ + void setPreemption(byte value); + + /** + * compress the priority and preemption to a single byte value; + * + * @return SessionClassID as byte + */ + byte toSingleByte(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/ISubscriberID.java b/packetcable-driver/src/main/java/org/pcmm/gates/ISubscriberID.java new file mode 100644 index 0000000..d71e194 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/ISubscriberID.java @@ -0,0 +1,49 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + +import java.net.InetAddress; + +import org.pcmm.base.IPCMMBaseObject; + +/** + *

+ * The SubscriberID, consisting of the IPv4 or IPv6 address of either the CM or + * client CPE device (either directly connected to the CM or on a routable + * network behind the CM), identifies the user requesting the service. In + * complex network environments this address may be used to route Gate Control + * messages between a number of Policy Servers and to determine which CMTS is + * providing service to a particular endpoint. In addition to the IPv4 or IPv6 + * address, a subscriber may also be identified via a FQDN or some opaque data + * (object defined below) relevant to the service in question. + *

+ *

+ * For a Multicast Gates the CMTS uses the SubscriberID to decide where the + * Multicast replication needs to be created. The CMTS treats the SubscriberID + * as the source IP address of a JoinMulticastSession [1]. If the SubscriberID + * is on an IP subnet that is not directly connected to the CMTS, the CMTS MAY + * reject the Gate as having an invalid SubscriberID see 6.4.2.14 PacketCable + * Error. + *

+ * + * + */ + +public interface ISubscriberID extends IPCMMBaseObject { + static final short LENGTH = 8; + static final byte SNUM = 3; + static final byte STYPE = 1; + + /** + * source IP address for the PCMM gate. + * + * @return IP v4 or v6 ip address. + */ + InetAddress getSourceIPAddress(); + + void setSourceIPAddress(InetAddress address); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/ITrafficProfile.java b/packetcable-driver/src/main/java/org/pcmm/gates/ITrafficProfile.java new file mode 100644 index 0000000..9e21675 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/ITrafficProfile.java @@ -0,0 +1,23 @@ +/** + @header@ + */ + + +package org.pcmm.gates; + +import org.pcmm.base.IPCMMBaseObject; + +public interface ITrafficProfile extends IPCMMBaseObject { + + static final byte SNUM = 7; + + /** + * 0x001, 0x011 and 0x111 (Authorized, Reserved, and Committed) are allowed + * + * @param en + */ + void setEnvelop(byte en); + + byte getEnvelop(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/ITransactionID.java b/packetcable-driver/src/main/java/org/pcmm/gates/ITransactionID.java new file mode 100644 index 0000000..e835b39 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/ITransactionID.java @@ -0,0 +1,43 @@ +/** + @header@ + */ +package org.pcmm.gates; + +import org.pcmm.base.IPCMMBaseObject; + +/** + */ +public interface ITransactionID extends IPCMMBaseObject { + + static final byte SNUM = 1; + static final byte STYPE = 1; + static final short LENGTH = 8; + + static final short GateSet = 4; + static final short GateSetAck = 5; + static final short GateSetErr = 6; + static final short GateInfo = 7; + static final short GateInfoAck = 8; + static final short GateInfoErr = 9; + static final short GateDelete = 10; + static final short GateDeleteAck = 11; + static final short GateDeleteErr = 12; + static final short GateReportState = 15; + static final short GateCmdErr = 16; + static final short PDPConfig = 17; + static final short PDPConfigAck = 18; + static final short PDPConfigErr = 19; + static final short SynchRequest = 20; + static final short SynchReport = 21; + static final short SynchComplete = 22; + static final short MsgReceipt = 23; + + void setTransactionIdentifier(short id); + + short getTransactionIdentifier(); + + void setGateCommandType(short type); + + short getGateCommandType(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/AMID.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/AMID.java new file mode 100644 index 0000000..4f1c3af --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/AMID.java @@ -0,0 +1,77 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.IAMID; + +/** + * + */ +public class AMID extends PCMMBaseObject implements IAMID { + + /** + * + */ + public AMID() { + this(LENGTH, STYPE, SNUM); + } + + /** + * @param data + */ + public AMID(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public AMID(short len, byte sType, byte sNum) { + super(len, sType, sNum); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IAMID#setApplicationType(short) + */ + @Override + public void setApplicationType(short type) { + setShort(type, (short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IAMID#getApplicationType() + */ + @Override + public short getApplicationType() { + return getShort((short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IAMID#setApplicationMgrTag(short) + */ + @Override + public void setApplicationMgrTag(short type) { + setShort(type, (short) 2); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IAMID#getApplicationMgrTag() + */ + @Override + public short getApplicationMgrTag() { + return getShort((short) 2); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/BestEffortService.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/BestEffortService.java new file mode 100644 index 0000000..4e0e9b0 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/BestEffortService.java @@ -0,0 +1,211 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import java.util.Arrays; + +// import org.junit.Assert; +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.ITrafficProfile; +import org.umu.cops.stack.COPSData; + +/** + * + */ +public class BestEffortService extends PCMMBaseObject implements + ITrafficProfile { + public static final byte STYPE = 3; + // XXX -> 60=0x3C, 112 = 0x70, 164=0xA4 + // Length = 44=0x2C, 80=0x50 or 116=0x74 + public static final short LENGTH = 44; + + public static final byte DEFAULT_TRAFFIC_PRIORITY = 0; + // Authorized + public static final byte DEFAULT_ENVELOP = 0x7; + + public static final int DEFAULT_MAX_TRAFFIC_BURST = 3044; + + private BEEnvelop authorizedEnvelop; + + private BEEnvelop reservedEnvelop; + + private BEEnvelop committedEnvelop; + + /** + * + * @param e + * envelop + */ + public BestEffortService(byte e) { + super((short) (e == 1 ? LENGTH : (e == 7 ? 116 : 80)), STYPE, SNUM); + setEnvelop(e); + authorizedEnvelop = new BEEnvelop(); + if (e > 1) { + reservedEnvelop = new BEEnvelop(); + if (e == 7) + committedEnvelop = new BEEnvelop(); + } + } + + public BestEffortService(byte[] bytes) { + super(bytes); + byte e = getEnvelop(); + authorizedEnvelop = new BEEnvelop(headPadding(offset, Arrays.copyOfRange(bytes, 8, LENGTH))); + if (e > 1) { + reservedEnvelop = new BEEnvelop(headPadding(offset, Arrays.copyOfRange(bytes, LENGTH, 80))); + if (e == 7) + committedEnvelop = new BEEnvelop(headPadding(offset, Arrays.copyOfRange(bytes, 80, 116))); + } + } + + @Override + public void setEnvelop(byte e) { + setLength((short) (e == 1 ? LENGTH : (e == 7 ? 116 : 80))); + // reset cops data to fit the new length + byte[] array = new byte[getLength() - offset]; + Arrays.fill(array, (byte) 0); + setData(new COPSData(array, 0, array.length)); + setByte(e, (short) 0); + } + + @Override + public byte getEnvelop() { + return getByte((short) 0); + } + + public BEEnvelop getAuthorizedEnvelop() { + return authorizedEnvelop; + } + + public BEEnvelop getReservedEnvelop() { + return reservedEnvelop; + } + + public BEEnvelop getCommittedEnvelop() { + return committedEnvelop; + } + + @Override + public byte[] getAsBinaryArray() { + byte[] returnBuffer = super.getAsBinaryArray(); + + {// fill buffer with the Authorized Envelop + byte[] authEnv = Arrays.copyOfRange(getAuthorizedEnvelop().getAsBinaryArray(), offset, BEEnvelop.LENGHT); + // offset + 4 since the Envelop data begin from byte nb 8 + System.arraycopy(authEnv, 0, returnBuffer, offset + 4, authEnv.length); + } + if (getReservedEnvelop() != null) { + byte[] reservedEnv = Arrays.copyOfRange(getReservedEnvelop().getAsBinaryArray(), offset, BEEnvelop.LENGHT); + System.arraycopy(reservedEnv, 0, returnBuffer, LENGTH, reservedEnv.length); + } + if (getCommittedEnvelop() != null) { + byte[] commitEnv = Arrays.copyOfRange(getCommittedEnvelop().getAsBinaryArray(), offset, BEEnvelop.LENGHT); + System.arraycopy(commitEnv, 0, returnBuffer, LENGTH + 36, commitEnv.length); + } + return returnBuffer; + } + + /** + * + * + */ + public static class BEEnvelop extends PCMMBaseObject { + // basically we need 36 bytes but since PCMMBasedObject needs 4 bytes + // more we allocate 40 bytes and then subtract them when setting BE + // data. + private final static short LENGHT = 40; + + protected BEEnvelop() { + super(LENGHT, (byte) 0, (byte) 0); + setTrafficPriority(DEFAULT_TRAFFIC_PRIORITY); + } + + protected BEEnvelop(byte[] buffer) { + super(buffer); + } + + public void setTrafficPriority(byte p) { + setByte(p, (short) 0); + } + + public byte getTrafficPriority() { + return getByte((short) 0); + } + + // + public void setRequestTransmissionPolicy(int p) { + setInt(p, (short) 4); + } + + public int getRequestTransmissionPolicy() { + return getInt((short) 4); + } + + public int getMaximumSustainedTrafficRate() { + return getInt((short) 8); + } + + public void setMaximumSustainedTrafficRate(int p) { + setInt(p, (short) 8); + } + + public int getMaximumTrafficBurst() { + return getInt((short) 12); + } + + public void setMaximumTrafficBurst(int p) { + setInt(p, (short) 12); + } + + public int getMinimumReservedTrafficRate() { + return getInt((short) 16); + } + + public void setMinimumReservedTrafficRate(int p) { + setInt(p, (short) 16); + } + + public short getAssumedMinimumReservedTrafficRatePacketSize() { + return getShort((short) 20); + } + + public void setAssumedMinimumReservedTrafficRatePacketSize(short p) { + setShort(p, (short) 20); + } + + public short getMaximumConcatenatedBurst() { + return getShort((short) 22); + } + + public void setMaximumConcatenatedBurst(short p) { + setShort(p, (short) 22); + } + + public int getRequiredAttributeMask() { + return getInt((short) 24); + } + + public void setRequiredAttributeMask(int p) { + setInt(p, (short) 24); + } + + public int getForbiddenAttributeMask() { + return getInt((short) 28); + } + + public void setForbiddenAttributeMask(int p) { + setInt(p, (short) 28); + } + + public int getAttributeAggregationRuleMask() { + return getInt((short) 32); + } + + public void setAttributeAggregationRuleMask(int p) { + setInt(p, (short) 32); + } + + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/Classifier.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/Classifier.java new file mode 100644 index 0000000..8384722 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/Classifier.java @@ -0,0 +1,193 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.IClassifier; + +/** + * + */ +public class Classifier extends PCMMBaseObject implements IClassifier { + + /** + * + */ + public Classifier() { + this(LENGTH, STYPE, SNUM); + } + + /** + * @param data + */ + public Classifier(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public Classifier(short len, byte sType, byte sNum) { + super(len, sType, sNum); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getDestinationIPAddress() + */ + @Override + public InetAddress getDestinationIPAddress() { + try { + return Inet4Address.getByAddress(getBytes((short) 8, (short) 4)); + } catch (UnknownHostException e) { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.gates.IClassifier#setDestinationIPAddress(java.net.InetAddress) + */ + @Override + public void setDestinationIPAddress(InetAddress address) { + setBytes(address.getAddress(), (short) 8); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getDestinationPort() + */ + @Override + public short getDestinationPort() { + return getShort((short) 14); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setDestinationPort(short) + */ + @Override + public void setDestinationPort(short p) { + setShort(p, (short) 14); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getSourceIPAddress() + */ + @Override + public InetAddress getSourceIPAddress() { + try { + return Inet4Address.getByAddress(getBytes((short) 4, (short) 4)); + } catch (UnknownHostException e) { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setSourceIPAddress(java.net.InetAddress) + */ + @Override + public void setSourceIPAddress(InetAddress a) { + setBytes(a.getAddress(), (short) 4); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getSourcePort() + */ + @Override + public short getSourcePort() { + return getShort((short) 12); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setSourcePort(short) + */ + @Override + public void setSourcePort(short p) { + setShort(p, (short) 12); + + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getProtocol() + */ + @Override + public Protocol getProtocol() { + return Protocol.valueOf(getShort((short) 0)); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setProtocol(short) + */ + @Override + public void setProtocol(Protocol p) { + setShort(p.getValue(), (short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getPriority() + */ + @Override + public byte getPriority() { + return getBytes((short) 16, (short) 1)[0]; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setPriority(byte) + */ + @Override + public void setPriority(byte p) { + setBytes(new byte[] { p }, (short) 16); + } + + @Override + public byte getDSCPTOS() { + return getBytes((short) 2, (short) 1)[0]; + } + + @Override + public void setDSCPTOS(byte v) { + setBytes(new byte[] { v }, (short) 2); + + } + + @Override + public byte getDSCPTOSMask() { + return getBytes((short) 3, (short) 1)[0]; + } + + @Override + public void setDSCPTOSMask(byte v) { + setBytes(new byte[] { v }, (short) 3); + + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/DOCSISServiceClassNameTrafficProfile.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/DOCSISServiceClassNameTrafficProfile.java new file mode 100644 index 0000000..854d543 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/DOCSISServiceClassNameTrafficProfile.java @@ -0,0 +1,76 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.ITrafficProfile; + +/** + * + */ +public class DOCSISServiceClassNameTrafficProfile extends PCMMBaseObject + implements ITrafficProfile { + + public static final byte STYPE = 2; + public static final short LENGTH = 12; + + /** + * + */ + public DOCSISServiceClassNameTrafficProfile() { + this(LENGTH, STYPE, SNUM); + } + + /** + * @param data + */ + public DOCSISServiceClassNameTrafficProfile(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public DOCSISServiceClassNameTrafficProfile(short len, byte sType, byte sNum) { + super(len, sType, sNum); + setEnvelop((byte) 0x7); + } + + /** + * @return the serviceClassName + */ + public String getServiceClassName() { + return new String(getBytes((short) 4, (short) 4)); + } + + /** + * @param serviceClassName + * the serviceClassName to set + */ + public void setServiceClassName(String serviceClassName) { + setBytes(serviceClassName.getBytes(), (short) 4); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ITrafficProfile#getEnvelop() + */ + @Override + public byte getEnvelop() { + return getBytes((short) 0, (short) 1)[0]; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ITrafficProfile#setEnvelop(byte) + */ + @Override + public void setEnvelop(byte en) { + setBytes(new byte[] { en }, (short) 0); + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/ExtendedClassifier.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/ExtendedClassifier.java new file mode 100644 index 0000000..0e68f50 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/ExtendedClassifier.java @@ -0,0 +1,347 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.IExtendedClassifier; + +/** + * + */ +public class ExtendedClassifier extends PCMMBaseObject implements + IExtendedClassifier { + + public ExtendedClassifier() { + this(LENGTH, STYPE, SNUM); + } + + /** + * @param data + */ + public ExtendedClassifier(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public ExtendedClassifier(short len, byte sType, byte sNum) { + super(len, sType, sNum); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getDestinationIPAddress() + */ + @Override + public InetAddress getDestinationIPAddress() { + try { + return InetAddress.getByAddress(getBytes((short) 12, (short) 4)); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.gates.IClassifier#setDestinationIPAddress(java.net.InetAddress) + */ + @Override + public void setDestinationIPAddress(InetAddress address) { + setBytes(address.getAddress(), (short) 12); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getDestinationPort() + */ + @Override + public short getDestinationPort() { + return getShort((short) 24); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setDestinationPort(short) + */ + @Override + public void setDestinationPort(short p) { + setShort(p, (short) 24); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getSourceIPAddress() + */ + @Override + public InetAddress getSourceIPAddress() { + try { + return InetAddress.getByAddress(getBytes((short) 4, (short) 4)); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setSourceIPAddress(java.net.InetAddress) + */ + @Override + public void setSourceIPAddress(InetAddress a) { + setBytes(a.getAddress(), (short) 4); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getSourcePort() + */ + @Override + public short getSourcePort() { + return getShort((short) 20); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setSourcePort(short) + */ + @Override + public void setSourcePort(short p) { + setShort(p, (short) 20); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getProtocol() + */ + @Override + public Protocol getProtocol() { + return Protocol.valueOf(getShort((short) 0)); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setProtocol(short) + */ + @Override + public void setProtocol(Protocol p) { + setShort(p.getValue(), (short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#getPriority() + */ + @Override + public byte getPriority() { + return getByte((short) 30); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IClassifier#setPriority(byte) + */ + @Override + public void setPriority(byte p) { + setByte(p, (short) 30); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getIPSourceMask() + */ + @Override + public InetAddress getIPSourceMask() { + try { + return InetAddress.getByAddress(getBytes((short) 8, (short) 4)); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.gates.IExtendedClassifier#setIPSourceMask(java.net.InetAddress) + */ + @Override + public void setIPSourceMask(InetAddress a) { + setBytes(a.getAddress(), (short) 8); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getIPDestinationMask() + */ + @Override + public InetAddress getIPDestinationMask() { + try { + return InetAddress.getByAddress(getBytes((short) 16, (short) 4)); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.gates.IExtendedClassifier#setIPDestinationMask(java.net.InetAddress + * ) + */ + @Override + public void setIPDestinationMask(InetAddress m) { + setBytes(m.getAddress(), (short) 16); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getSourcePortStart() + */ + @Override + public short getSourcePortStart() { + return getShort((short) 20); + } + + @Override + public void setSourcePortStart(short p) { + setShort(p, (short) 20); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getSourcePortEnd() + */ + @Override + public short getSourcePortEnd() { + return getShort((short) 22); + } + + @Override + public void setSourcePortEnd(short p) { + setShort(p, (short) 22); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getDestinationPortStart() + */ + @Override + public short getDestinationPortStart() { + return getShort((short) 24); + } + + @Override + public void setDestinationPortStart(short p) { + setShort(p, (short) 24); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getDestinationPortEnd() + */ + @Override + public short getDestinationPortEnd() { + return getShort((short) 26); + } + + @Override + public void setDestinationPortEnd(short p) { + setShort(p, (short) 26); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getClassifierID() + */ + @Override + public short getClassifierID() { + return getShort((short) 28); + } + + @Override + public void setClassifierID(short p) { + setShort(p, (short) 28); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getActivationState() + */ + @Override + public byte getActivationState() { + return getByte((short) 31); + } + + @Override + public void setActivationState(byte s) { + setByte(s, (short) 31); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IExtendedClassifier#getAction() + */ + @Override + public byte getAction() { + return getByte((short) 32); + } + + @Override + public void setAction(byte a) { + setByte(a, (short) 32); + } + + @Override + public byte getDSCPTOS() { + return getByte((short) 2); + } + + @Override + public void setDSCPTOS(byte v) { + setByte(v, (short) 2); + } + + @Override + public byte getDSCPTOSMask() { + return getByte((short) 3); + } + + @Override + public void setDSCPTOSMask(byte v) { + setByte(v, (short) 3); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateID.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateID.java new file mode 100644 index 0000000..26153a6 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateID.java @@ -0,0 +1,57 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.IGateID; + +/** + * + */ +public class GateID extends PCMMBaseObject implements IGateID { + + /** + * + */ + public GateID() { + this(LENGTH, STYPE, SNUM); + } + + /** + * @param data + */ + public GateID(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public GateID(short len, byte sType, byte sNum) { + super(len, sType, sNum); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IGateID#setGateID(int) + */ + @Override + public void setGateID(int gateID) { + setInt(gateID, (short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IGateID#getGateID() + */ + @Override + public int getGateID() { + return getInt((short) 0); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateSpec.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateSpec.java new file mode 100644 index 0000000..dce286e --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/GateSpec.java @@ -0,0 +1,105 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.IGateSpec; +import org.pcmm.gates.ISessionClassID; + +/** + * + */ +public class GateSpec extends PCMMBaseObject implements IGateSpec { + + public GateSpec() { + super(LENGTH, STYPE, SNUM); + } + + public GateSpec(byte[] data) { + super(data); + } + + @Override + public ISessionClassID getSessionClassID() { + return new SessionClassID(getByte((short) 3)); + } + + @Override + public void setSessionClassID(ISessionClassID id) { + setByte(id.toSingleByte(), (short) 3); + } + + @Override + public Direction getDirection() { + return Direction.valueOf(getByte((short) 0)); + } + + @Override + public void setDirection(Direction direction) { + setByte(direction.getValue(), (short) 0); + } + + @Override + public short getTimerT1() { + return getShort((short) 4); + } + + @Override + public void setTimerT1(short authTimer) { + setShort(authTimer, (short) 4); + } + + @Override + public short getTimerT2() { + return getShort((short) 6); + } + + @Override + public void setTimerT2(short timer) { + setShort(timer, (short) 6); + + } + + @Override + public short getTimerT3() { + return getShort((short) 8); + } + + @Override + public void setTimerT3(short t) { + setShort(t, (short) 8); + + } + + @Override + public short getTimerT4() { + return getShort((short) 10); + } + + @Override + public void setTimerT4(short t) { + setShort(t, (short) 10); + } + + @Override + public void setDSCP_TOSOverwrite(DSCPTOS dscpTos) { + setByte(dscpTos.getValue(), (short) 1); + } + + @Override + public DSCPTOS getDSCP_TOSOverwrite() { + return DSCPTOS.valueOf(getByte((short) 1)); + } + + @Override + public byte getDSCP_TOSMask() { + return getByte((short) 2); + } + + @Override + public void setDSCP_TOSMask(byte dscp_tos_mask) { + setByte(dscp_tos_mask, (short) 2); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMError.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMError.java new file mode 100644 index 0000000..da686ef --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMError.java @@ -0,0 +1,98 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.IPCMMError; + +/** + * + */ +public class PCMMError extends PCMMBaseObject implements IPCMMError { + /** + * + */ + public PCMMError() { + this(LENGTH, STYPE, SNUM); + } + + public PCMMError(short errorCode, short subErrCode) { + this(); + setErrorCode(errorCode); + setErrorSubcode(subErrCode); + } + + /** + * @param data + */ + public PCMMError(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public PCMMError(short len, byte sType, byte sNum) { + super(len, sType, sNum); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCError#setErrorCode(int) + */ + @Override + public void setErrorCode(short errorCode) { + setShort(errorCode, (short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCError#getErrorCode() + */ + @Override + public short getErrorCode() { + return getShort((short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCError#setErrorSubcode(int) + */ + @Override + public void setErrorSubcode(short errorSubcode) { + setShort(errorSubcode, (short) 2); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCError#getErrorCode() + */ + @Override + public short getErrorSubcode() { + return getShort((short) 2); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCError#getDescription() + */ + @Override + public String getDescription() { + String hex = Integer.toHexString(getErrorSubcode() & 0xFFFF); + return "Error Code: " + getErrorCode() + " Error Subcode : " + hex + + " " + Description.valueOf(getErrorCode()); + } + + @Override + public String toString() { + return getDescription(); + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMGateReq.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMGateReq.java new file mode 100644 index 0000000..0630a9f --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/PCMMGateReq.java @@ -0,0 +1,273 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import java.util.Arrays; + +import org.pcmm.base.IPCMMBaseObject; +import org.pcmm.gates.IAMID; +import org.pcmm.gates.IClassifier; +import org.pcmm.gates.IGateID; +import org.pcmm.gates.IGateSpec; +import org.pcmm.gates.IPCMMError; +import org.pcmm.gates.IPCMMGate; +import org.pcmm.gates.ISubscriberID; +import org.pcmm.gates.ITrafficProfile; +import org.pcmm.gates.ITransactionID; + +/** + *

+ * = [] + * + *

+ */ +public class PCMMGateReq implements IPCMMGate { + + private boolean multicast; + private IGateID gateID; + private IAMID iamid; + private IPCMMError error; + private ISubscriberID subscriberID; + private ITransactionID transactionID; + private IGateSpec gateSpec; + private ITrafficProfile trafficProfile; + private IClassifier classifier; + + public PCMMGateReq() { + } + + public PCMMGateReq(byte[] data) { + short len, offset; + byte sNum, sType; + len = offset = 0; + sNum = sType = (byte) 0; + while (offset + 5 < data.length) { + len = 0; + len |= ((short) data[offset]) << 8; + len |= ((short) data[offset + 1]) & 0xFF; + sNum = data[offset + 2]; + sType = data[offset + 3]; + byte[] dataBuffer = Arrays.copyOfRange(data, offset, offset + len); + switch (sNum) { + case IGateID.SNUM: + setGateID(new GateID(dataBuffer)); + break; + case IAMID.SNUM: + setAMID(new AMID(dataBuffer)); + break; + case ISubscriberID.SNUM: + setSubscriberID(new SubscriberID(dataBuffer)); + break; + case ITransactionID.SNUM: + setTransactionID(new TransactionID(dataBuffer)); + break; + case IGateSpec.SNUM: + setGateSpec(new GateSpec(dataBuffer)); + break; + case ITrafficProfile.SNUM: + setTrafficProfile(new BestEffortService(dataBuffer)); + break; + case IClassifier.SNUM: + setClassifier(new Classifier(dataBuffer)); + break; + case IPCMMError.SNUM: + error = new PCMMError(dataBuffer); + break; + default: + System.out.println("unhandled Object skept : S-NUM=" + sNum + + " S-TYPE=" + sType + " LEN=" + len); + } + offset += len; + } + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#isMulticast() + */ + @Override + public boolean isMulticast() { + // TODO Auto-generated method stub + return multicast; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#setGateID(short) + */ + @Override + public void setGateID(IGateID gateid) { + this.gateID = gateid; + + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#setAMID(org.pcmm.gates.IAMID) + */ + @Override + public void setAMID(IAMID iamid) { + this.iamid = iamid; + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.gates.IPCMMGate#getSubscriberID(org.pcmm.gates.ISubscriberID) + */ + @Override + public void setSubscriberID(ISubscriberID subscriberID) { + this.subscriberID = subscriberID; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getGateSpec(org.pcmm.gates.IGateSpec) + */ + @Override + public void setGateSpec(IGateSpec gateSpec) { + this.gateSpec = gateSpec; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getClassifier(org.pcmm.gates.IClassifier) + */ + @Override + public void setClassifier(IClassifier classifier) { + this.classifier = classifier; + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.gates.IPCMMGate#getTrafficProfile(org.pcmm.gates.ITrafficProfile + * ) + */ + @Override + public void setTrafficProfile(ITrafficProfile profile) { + this.trafficProfile = profile; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getGateID() + */ + @Override + public IGateID getGateID() { + return gateID; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getAMID() + */ + @Override + public IAMID getAMID() { + return iamid; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getSubscriberID() + */ + @Override + public ISubscriberID getSubscriberID() { + return subscriberID; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getGateSpec() + */ + @Override + public IGateSpec getGateSpec() { + return gateSpec; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getClassifier() + */ + @Override + public IClassifier getClassifier() { + return classifier; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.IPCMMGate#getTrafficProfile() + */ + @Override + public ITrafficProfile getTrafficProfile() { + return trafficProfile; + } + + @Override + public void setTransactionID(ITransactionID transactionID) { + this.transactionID = transactionID; + } + + @Override + public ITransactionID getTransactionID() { + return transactionID; + } + + public IPCMMError getError() { + return error; + } + + public void setError(IPCMMError error) { + this.error = error; + } + + @Override + public byte[] getData() { + byte[] array = new byte[0]; + if (getTransactionID() != null) { + array = fill(array, getTransactionID()); + } + if (getGateID() != null) { + array = fill(array, getGateID()); + } + if (getAMID() != null) { + array = fill(array, getAMID()); + + } + if (getSubscriberID() != null) { + array = fill(array, getSubscriberID()); + } + if (getGateSpec() != null) { + array = fill(array, getGateSpec()); + } + if (getTrafficProfile() != null) { + array = fill(array, getTrafficProfile()); + } + if (getClassifier() != null) { + array = fill(array, getClassifier()); + } + return array; + } + + private byte[] fill(byte[] array, IPCMMBaseObject obj) { + byte[] a = obj.getAsBinaryArray(); + int offset = array.length; + array = Arrays.copyOf(array, offset + a.length); + System.arraycopy(a, 0, array, offset, a.length); + return array; + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/SessionClassID.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/SessionClassID.java new file mode 100644 index 0000000..7b3ff20 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/SessionClassID.java @@ -0,0 +1,85 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import org.pcmm.gates.ISessionClassID; + +/** + * + */ +public class SessionClassID implements ISessionClassID { + + private byte priority; + private byte preemption; + + // TODO check this; + private byte session; + + public SessionClassID() { + this((byte) 0); + } + + public SessionClassID(byte value) { + session = value; + priority = 0; + preemption = 0; + priority |= value >> 2; + preemption |= value >> 3; + + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ISessionClassID#getPriority() + */ + @Override + public byte getPriority() { + return priority; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ISessionClassID#setPriority(byte) + */ + @Override + public void setPriority(byte value) { + this.priority = value; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ISessionClassID#getPreemption() + */ + @Override + public byte getPreemption() { + return preemption; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ISessionClassID#setPreemption(byte) + */ + @Override + public void setPreemption(byte value) { + this.preemption = value; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ISessionClassID#toSingleByte() + */ + @Override + public byte toSingleByte() { + // byte ret = 0; + // ret |= (priority << 2); + // ret |= (preemption & 0xf); + // return ret; + return session; + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/SubscriberID.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/SubscriberID.java new file mode 100644 index 0000000..e933bb2 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/SubscriberID.java @@ -0,0 +1,66 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.ISubscriberID; + +/** + * + */ +public class SubscriberID extends PCMMBaseObject implements ISubscriberID { + + /** + * + */ + public SubscriberID() { + this(LENGTH, STYPE, SNUM); + } + + /** + * @param data + */ + public SubscriberID(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public SubscriberID(short len, byte sType, byte sNum) { + super(len, sType, sNum); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ISubscriberID#getSourceIPAddress() + */ + @Override + public InetAddress getSourceIPAddress() { + try { + return Inet4Address.getByAddress(getBytes((short) 0, (short) 4)); + } catch (UnknownHostException e) { + return null; + } + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.gates.ISubscriberID#setSourceIPAddress(java.net.InetAddress) + */ + @Override + public void setSourceIPAddress(InetAddress address) { + setBytes(address.getAddress(), (short) 0); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/TransactionID.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/TransactionID.java new file mode 100644 index 0000000..16ae63d --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/TransactionID.java @@ -0,0 +1,77 @@ +/** + @header@ + */ +package org.pcmm.gates.impl; + +import org.pcmm.base.impl.PCMMBaseObject; +import org.pcmm.gates.ITransactionID; + +/** + * + */ +public class TransactionID extends PCMMBaseObject implements ITransactionID { + + /** + * + */ + public TransactionID() { + this(LENGTH, STYPE, SNUM); + } + + /** + * @param data + */ + public TransactionID(byte[] data) { + super(data); + } + + /** + * @param len + * @param sType + * @param sNum + */ + public TransactionID(short len, byte sType, byte sNum) { + super(len, sType, sNum); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ITransactionID#setTransactionIdentifier(short) + */ + @Override + public void setTransactionIdentifier(short id) { + setShort(id, (short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ITransactionID#getTransactionIdentifier() + */ + @Override + public short getTransactionIdentifier() { + return getShort((short) 0); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ITransactionID#setGateCommandType(short) + */ + @Override + public void setGateCommandType(short type) { + setShort(type, (short) 2); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.gates.ITransactionID#getGateCommandType() + */ + @Override + public short getGateCommandType() { + return getShort((short) 2); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/gates/impl/package-info.java b/packetcable-driver/src/main/java/org/pcmm/gates/impl/package-info.java new file mode 100644 index 0000000..d845cbf --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/gates/impl/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +/** + * + */ +package org.pcmm.gates.impl; diff --git a/packetcable-driver/src/main/java/org/pcmm/messages/IMessage.java b/packetcable-driver/src/main/java/org/pcmm/messages/IMessage.java new file mode 100644 index 0000000..e7e5407 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/messages/IMessage.java @@ -0,0 +1,47 @@ +/** + @header@ + */ + +package org.pcmm.messages; + +/** + * This defines the messages exchanged between client and server. + * + * + *
+ * 1 = Request                 (REQ)
+ * 2 = Decision                (DEC)
+ * 3 = Report State            (RPT)
+ * 4 = Delete Request State    (DRQ)
+ * 5 = Synchronize State Req   (SSQ)
+ * 6 = Client-Open             (OPN)
+ * 7 = Client-Accept           (CAT)
+ * 8 = Client-Close            (CC)
+ * 9 = Keep-Alive              (KA)
+ * 10= Synchronize Complete    (SSC)
+ * 
+ * + */ +public interface IMessage { + + public static enum MessageProperties { + CLIENT_TYPE("Client-Type"), PEP_ID("Pep-ID"), KA_TIMER("KA-Timer"), ACCEPT_TIMER( + "Accept-Timer"), ERR_MESSAGE("Error-Message"), ERR_MESSAGE_SUB_CODE( + "Error-Message-Code"), MM_MAJOR_VERSION_INFO( + "MM-Major-Version-info"), MM_MINOR_VERSION_INFO( + "MM-Minor-Version-info"), R_TYPE("R-Type"), M_TYPE("M-Type"), CLIENT_HANDLE( + "Client-Handle"), GATE_CONTROL("Gate-Control"), DECISION_CMD_CODE( + "Decision-Type"), DECISION_FLAG("Decision-Flag"); + + private MessageProperties(String valueString) { + this.value = valueString; + } + + private String value; + + public String getValue() { + return value; + } + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/messages/IMessageFactory.java b/packetcable-driver/src/main/java/org/pcmm/messages/IMessageFactory.java new file mode 100644 index 0000000..3a77579 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/messages/IMessageFactory.java @@ -0,0 +1,37 @@ +/** + @header@ + */ +package org.pcmm.messages; + +import java.util.Properties; + +import org.umu.cops.stack.COPSMsg; + +/** + * + * Factory used to create {@code COPSMsg} based on message type input and a list + * of properties. + * + */ +public interface IMessageFactory { + + /** + * creates a new message with the specified message type. + * + * @param messageType + * message type + * @return new message. + */ + COPSMsg create(byte messageType); + + /** + * creates a new message with the specified message type and content + * + * @param messageType + * message type + * @param properties + * message content. + * @return new message. + */ + COPSMsg create(byte messageType, Properties properties); +} diff --git a/packetcable-driver/src/main/java/org/pcmm/messages/impl/COPSDecisionMsgEX.java b/packetcable-driver/src/main/java/org/pcmm/messages/impl/COPSDecisionMsgEX.java new file mode 100644 index 0000000..7b22b9c --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/messages/impl/COPSDecisionMsgEX.java @@ -0,0 +1,476 @@ +/** + @header@ + */ +package org.pcmm.messages.impl; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSIntegrity; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSObjHeader; + +/** + * COPS Decision Message + * + * + */ + +public class COPSDecisionMsgEX extends COPSMsg { + + /* COPSHeader coming from base class */ + private COPSHandle _clientHandle; + private COPSError _error; + private Hashtable _decisions; + private COPSIntegrity _integrity; + private COPSContext _decContext; + private COPSClientSI clientSI; + + // / + public COPSDecisionMsgEX() { + _clientHandle = null; + _error = null; + _decisions = new Hashtable(20); + _integrity = null; + _decContext = null; + clientSI = null; + } + + /** + * Checks the sanity of COPS message and throw an COPSBadDataException when + * data is bad. + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_clientHandle == null) + || ((_error == null) && (_decisions.size() == 0))) { + throw new COPSException("Bad message format"); + } + } + + // / + protected COPSDecisionMsgEX(byte[] data) throws COPSException { + _decisions = new Hashtable(20); + _clientHandle = null; + _error = null; + _integrity = null; + _decContext = null; + clientSI = null; + parse(data); + } + + /** + * Parses the data and fills COPSDecisionMsg with its constituents + * + * @param data + * a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + super.parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data, _dataStart, buf, 0, data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader(buf) { + }; + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_HANDLE: { + _clientHandle = new COPSHandle(buf) { + }; + _dataStart += _clientHandle.getDataLength(); + } + break; + case COPSObjHeader.COPS_CONTEXT: { + // dec context + _decContext = new COPSContext(buf) { + }; + _dataStart += _decContext.getDataLength(); + } + break; + case COPSObjHeader.COPS_ERROR: { + _error = new COPSError(buf) { + }; + _dataStart += _error.getDataLength(); + } + break; + case COPSObjHeader.COPS_DEC: { + COPSDecision decs = new COPSDecision(buf) { + }; + _dataStart += decs.getDataLength(); + addDecision(decs, _decContext); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + case COPSObjHeader.COPS_CSI: { + clientSI = new COPSClientSI(buf) { + }; + _dataStart += clientSI.getDataLength(); + } + break; + default: { + throw new COPSException( + "Bad Message format, unknown object type"); + } + } + } + checkSanity(); + } + + /** + * Parses the data and fills that follows the header hdr and fills + * COPSDecisionMsg + * + * @param hdr + * a COPSHeader + * @param data + * a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Add message header + * + * @param hdr + * a COPSHeader + * + * @throws COPSException + * + */ + public void add(COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_DEC) + throw new COPSException("Error Header (no COPS_OP_DEC)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add client handle to the message + * + * @param handle + * a COPSHandle + * + * @throws COPSException + * + */ + public void add(COPSHandle handle) throws COPSException { + if (handle == null) + throw new COPSException("Null Handle"); + _clientHandle = handle; + setMsgLength(); + } + + /** + * Add an Error object + * + * @param error + * a COPSError + * + * @throws COPSException + * + */ + public void add(COPSError error) throws COPSException { + if (_decisions.size() != 0) + throw new COPSException("No null decisions"); + if (_error != null) + throw new COPSException("No null error"); + // Message integrity object should be the very last one + // If it is already added + if (_integrity != null) + throw new COPSException("No null integrity"); + _error = error; + setMsgLength(); + } + + /** + * Add one or more local decision object for a given decision context the + * context is optional, if null all decision object are tided to message + * context + * + * @param decision + * a COPSDecision + * @param context + * a COPSContext + * + * @throws COPSException + * + */ + public void addDecision(COPSDecision decision, COPSContext context) + throws COPSException { + // Either error or decision can be added + // If error is aleady there assert + if (_error != null) + throw new COPSException("No null error"); + + if (decision.isLocalDecision()) + throw new COPSException("Is local decision"); + + Vector v = (Vector) _decisions.get(context); + if (v == null) + v = new Vector(); + + if (decision.isFlagSet()) {// Commented out as advised by Felix + // if (v.size() != 0) + // { + // Only one set of decision flags is allowed + // for each context + // throw new COPSException + // ("Bad Message format, only one set of decision flags is allowed."); + // } + } else { + if (v.size() == 0) { + // The flags decision must precede any other + // decision message, since the decision is not + // flags throw exception + throw new COPSException( + "Bad Message format, flags decision must precede any other decision object."); + } + } + v.add(decision); + _decisions.put(context, v); + + setMsgLength(); + } + + /** + * Add integrity object + * + * @param integrity + * a COPSIntegrity + * + * @throws COPSException + * + */ + public void add(COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * Add a client specific informations + * + * @param clientSI + * a COPSClientSI + * + * @throws COPSException + * + */ + public void add(COPSClientSI clientSI) throws COPSException { + if (clientSI == null) + throw new COPSException("Null ClientSI"); + this.clientSI = clientSI; + setMsgLength(); + } + + /** + * Writes data to given socket + * + * @param id + * a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null) + _hdr.writeData(id); + if (_clientHandle != null) + _clientHandle.writeData(id); + if (_error != null) + _error.writeData(id); + + // Display decisions + // Display any local decisions + for (Enumeration e = _decisions.keys(); e.hasMoreElements();) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + context.writeData(id); + + for (Enumeration ee = v.elements(); ee.hasMoreElements();) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + decision.writeData(id); + } + } + if (clientSI != null) + clientSI.writeData(id); + if (_integrity != null) + _integrity.writeData(id); + } + + /** + * Method getHeader + * + * @return a COPSHeader + * + */ + public COPSHeader getHeader() { + return _hdr; + } + + /** + * Method getClientHandle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _clientHandle; + } + + public COPSClientSI getClientSI() { + return clientSI; + } + + /** + * Returns true if it has error object + * + * @return a boolean + * + */ + public boolean hasError() { + return (_error != null); + }; + + /** + * Should check hasError() before calling + * + * @return a COPSError + * + */ + public COPSError getError() { + return _error; + }; + + /** + * Returns a map of decision for which is an arry of context and vector of + * associated decision object. + * + * @return a Hashtable + * + */ + public Hashtable getDecisions() { + return _decisions; + }; + + /** + * Returns true if it has integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + }; + + /** + * Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return _integrity; + }; + + /** + * Method setMsgLength + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + short len = 0; + if (_clientHandle != null) + len += _clientHandle.getDataLength(); + if (_error != null) + len += _error.getDataLength(); + + // Display any local decisions + for (Enumeration e = _decisions.keys(); e.hasMoreElements();) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + len += context.getDataLength(); + + for (Enumeration ee = v.elements(); ee.hasMoreElements();) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + len += decision.getDataLength(); + } + } + if (clientSI != null) + len += clientSI.getDataLength(); + if (_integrity != null) { + len += _integrity.getDataLength(); + } + + _hdr.setMsgLength((int) len); + } + + /** + * Write an object textual description in the output stream + * + * @param os + * an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_clientHandle != null) + _clientHandle.dump(os); + if (_error != null) + _error.dump(os); + + // Display any local decisions + for (Enumeration e = _decisions.keys(); e.hasMoreElements();) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + context.dump(os); + + for (Enumeration ee = v.elements(); ee.hasMoreElements();) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + decision.dump(os); + } + } + if (clientSI != null) + clientSI.dump(os); + if (_integrity != null) { + _integrity.dump(os); + } + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/messages/impl/MessageFactory.java b/packetcable-driver/src/main/java/org/pcmm/messages/impl/MessageFactory.java new file mode 100644 index 0000000..25d26f9 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/messages/impl/MessageFactory.java @@ -0,0 +1,299 @@ +/** + * @header@ + */ +package org.pcmm.messages.impl; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Properties; + +import org.pcmm.messages.IMessage.MessageProperties; +import org.pcmm.messages.IMessageFactory; +import org.pcmm.objects.MMVersionInfo; +import org.pcmm.rcd.ICMTS; +import org.pcmm.rcd.IPCMMClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKAMsg; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSObjHeader; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSReqMsg; + +/** + * + * + */ +public class MessageFactory implements IMessageFactory { + + /** Default keep-alive timer value (secs) */ + public static final short KA_TIMER_VALUE = 30; + /** Default accounting timer value (secs) */ + public static final short ACCT_TIMER_VALUE = 0; + + private Logger logger = LoggerFactory.getLogger(getClass().getName()); + + private static MessageFactory instance; + + private MessageFactory() { + } + + public static MessageFactory getInstance() { + if (instance == null) + instance = new MessageFactory(); + return instance; + } + + /* + * (non-Javadoc) + * + * @see pcmm.messages.IMessageFactory#create(pcmm.messages.MessageType) + */ + public COPSMsg create(byte messageType) { + return create(messageType, new Properties()); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.messages.IMessageFactory#create(org.pcmm.messages.IMessage. + * MessageType, java.util.Properties) + */ + public COPSMsg create(byte messageType, Properties properties) { + // return new PCMMMessage(messageType, content); + switch (messageType) { + case COPSHeader.COPS_OP_OPN: + return createOPNMessage(properties); + case COPSHeader.COPS_OP_REQ: + return createREQMessage(properties); + case COPSHeader.COPS_OP_CAT: + return createCATMessage(properties); + case COPSHeader.COPS_OP_CC: + return createCCMessage(properties); + case COPSHeader.COPS_OP_DEC: + return createDECMessage(properties); + case COPSHeader.COPS_OP_DRQ: + break; + case COPSHeader.COPS_OP_KA: + return createKAMessage(properties); + case COPSHeader.COPS_OP_RPT: + break; + case COPSHeader.COPS_OP_SSC: + break; + case COPSHeader.COPS_OP_SSQ: + break; + } + return null; + } + + /** + * + * @param prop + * @return + */ + protected COPSMsg createDECMessage(Properties prop) { + COPSDecisionMsg msg = new COPSDecisionMsg(); + // ===common part between all gate control messages + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DEC, IPCMMClient.CLIENT_TYPE); + // handle + COPSHandle handle = new COPSHandle(); + // context + COPSContext context = new COPSContext(COPSContext.CONFIG, (short) 0); + // decision + COPSDecision decision = new COPSDecision(); + if (prop.get(MessageProperties.DECISION_CMD_CODE) != null) + decision.setCmdCode((byte) prop.get(MessageProperties.DECISION_CMD_CODE)); + if (prop.get(MessageProperties.DECISION_FLAG) != null) + decision.setFlags((short) prop.get(MessageProperties.DECISION_FLAG)); + COPSClientSI si = new COPSClientSI(COPSObjHeader.COPS_DEC, (byte) 4); + if (prop.get(MessageProperties.GATE_CONTROL) != null) + si.setData((COPSData) prop.get(MessageProperties.GATE_CONTROL)); + try { + msg.add(hdr); + if (prop.get(MessageProperties.CLIENT_HANDLE) != null) + handle.setId(new COPSData((String) prop.get(MessageProperties.CLIENT_HANDLE))); + msg.add(handle); + msg.addDecision(decision, context); + msg.add(si); + // try { + // msg.dump(System.out); + // } catch (IOException unae) { + // } + + } catch (COPSException e) { + logger.error(e.getMessage()); + } + + return msg; + } + + /** + * creates a Client-Open message. + * + * @param prop + * properties + * @return COPS message + */ + protected COPSMsg createOPNMessage(Properties prop) { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_OPN, IPCMMClient.CLIENT_TYPE); + COPSPepId pepId = new COPSPepId(); + // version infor object + short majorVersion = MMVersionInfo.DEFAULT_MAJOR_VERSION_INFO; + short minorVersion = MMVersionInfo.DEFAULT_MINOR_VERSION_INFO; + if (prop.get(MessageProperties.MM_MAJOR_VERSION_INFO) != null) + majorVersion = (Short) prop.get(MessageProperties.MM_MAJOR_VERSION_INFO); + if (prop.get(MessageProperties.MM_MINOR_VERSION_INFO) != null) + minorVersion = (Short) prop.get(MessageProperties.MM_MINOR_VERSION_INFO); + // Mandatory MM version. + COPSClientSI clientSI = new COPSClientSI((byte) 1); + byte[] versionInfo = new MMVersionInfo(majorVersion, minorVersion).getAsBinaryArray(); + clientSI.setData(new COPSData(versionInfo, 0, versionInfo.length)); + COPSClientOpenMsg msg = new COPSClientOpenMsg(); + try { + COPSData d = null; + if (prop.get(MessageProperties.PEP_ID) != null) + d = new COPSData((String) prop.get(MessageProperties.PEP_ID)); + else + d = new COPSData(InetAddress.getLocalHost().getHostName()); + pepId.setData(d); + msg.add(hdr); + msg.add(pepId); + msg.add(clientSI); + } catch (COPSException e) { + logger.error(e.getMessage()); + } catch (UnknownHostException e) { + logger.error(e.getMessage()); + } + return msg; + } + + /** + * creates a Client-Accept message. + * + * @param prop + * properties + * @return COPS message + */ + protected COPSMsg createCATMessage(Properties prop) { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_CAT, IPCMMClient.CLIENT_TYPE); + COPSKATimer katimer = null; + COPSAcctTimer acctTimer = null; + if (prop.get(MessageProperties.KA_TIMER) != null) + katimer = new COPSKATimer((short) prop.get(MessageProperties.KA_TIMER)); + else + katimer = new COPSKATimer((short) KA_TIMER_VALUE); + if (prop.get(MessageProperties.ACCEPT_TIMER) != null) + acctTimer = new COPSAcctTimer((short) prop.get(MessageProperties.ACCEPT_TIMER)); + else + acctTimer = new COPSAcctTimer(ACCT_TIMER_VALUE); + COPSClientAcceptMsg acceptMsg = new COPSClientAcceptMsg(); + try { + acceptMsg.add(hdr); + acceptMsg.add(katimer); + if (acctTimer.getTimerVal() != 0) + acceptMsg.add(acctTimer); + } catch (COPSException e) { + logger.error(e.getMessage()); + } + return acceptMsg; + } + + /** + * creates a Client-Close message. + * + * @param prop + * properties + * @return COPS message + */ + protected COPSMsg createCCMessage(Properties prop) { + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, IPCMMClient.CLIENT_TYPE); + COPSError err = null; + if (prop.get(MessageProperties.ERR_MESSAGE) != null) { + short code = (short) 0; + short error = (short) prop.get(MessageProperties.ERR_MESSAGE); + if (prop.get(MessageProperties.ERR_MESSAGE_SUB_CODE) != null) + code = (short) prop.get(MessageProperties.ERR_MESSAGE_SUB_CODE); + err = new COPSError(error, code); + } else + err = new COPSError(COPSError.COPS_ERR_UNKNOWN, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + try { + closeMsg.add(cHdr); + closeMsg.add(err); + } catch (COPSException e) { + logger.error(e.getMessage()); + } + return closeMsg; + } + + /** + * creates a Request message + * + * @param prop + * properties + * @return Request message + */ + protected COPSMsg createREQMessage(Properties prop) { + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_REQ, IPCMMClient.CLIENT_TYPE); + COPSReqMsg req = new COPSReqMsg(); + short rType = ICMTS.DEFAULT_R_TYPE; + short mType = ICMTS.DEFAULT_M_TYPE; + if (prop.get(MessageProperties.R_TYPE) != null) + rType = (Short) prop.get(MessageProperties.R_TYPE); + if (prop.get(MessageProperties.M_TYPE) != null) + mType = (Short) prop.get(MessageProperties.M_TYPE); + COPSContext copsContext = new COPSContext(rType, mType); + COPSHandle copsHandle = new COPSHandle(); + if (prop.get(MessageProperties.CLIENT_HANDLE) != null) + copsHandle.setId(new COPSData((String) prop.get(MessageProperties.CLIENT_HANDLE))); + else + // just a random handle + copsHandle.setId(new COPSData("" + Math.random() * 82730)); + try { + req.add(cHdr); + req.add(copsContext); + req.add(copsHandle); + } catch (COPSException e) { + logger.error(e.getMessage()); + } + return req; + } + + /** + * creates a Keep-Alive message. + * + * @param prop + * properties + * @return COPS message + */ + protected COPSMsg createKAMessage(Properties prop) { + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_KA, (short) 0); + COPSKAMsg kaMsg = new COPSKAMsg(); + COPSKATimer timer = null; + if (prop.get(MessageProperties.KA_TIMER) != null) + timer = new COPSKATimer((Short) prop.get(MessageProperties.KA_TIMER)); + else + timer = new COPSKATimer(); + try { + kaMsg.add(cHdr); + } catch (COPSException e) { + logger.error(e.getMessage()); + } + return kaMsg; + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/messages/package-info.java b/packetcable-driver/src/main/java/org/pcmm/messages/package-info.java new file mode 100644 index 0000000..66ddf11 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/messages/package-info.java @@ -0,0 +1,7 @@ +/** + * Package defining the messages exchanged between PCMM client and server. + */ +/** + * + */ +package org.pcmm.messages; diff --git a/packetcable-driver/src/main/java/org/pcmm/nio/PCMMChannel.java b/packetcable-driver/src/main/java/org/pcmm/nio/PCMMChannel.java new file mode 100644 index 0000000..f87677a --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/nio/PCMMChannel.java @@ -0,0 +1,172 @@ +/** + * + */ +package org.pcmm.nio; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.util.Date; + +import org.pcmm.PCMMProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSMsgParser; + +/** + * this class provides a set of utilities to efficiently read/write data from a + * stream, it could parameterized with a reading timeout or -1 for blocking + * until get a message + * + */ +public class PCMMChannel { + + private Logger logger = LoggerFactory.getLogger(getClass().getName()); + private ByteBuffer dataBuffer; + private Socket socket; + private int timeout; + public static final int DEFAULT_BYTE_BUFFER_SIZE = 2048; + public static final int DEFAULT_READ_TIMEOUT = -1; + + public PCMMChannel(Socket socket) { + this(socket, PCMMProperties.get(PCMMProperties.DEFAULT_TIEMOUT, + Integer.class, DEFAULT_READ_TIMEOUT)); + } + + public PCMMChannel(Socket socket, int timeout) { + this.socket = socket; + dataBuffer = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE); + logger.info("Allocated byte buffer with size = " + + DEFAULT_BYTE_BUFFER_SIZE); + this.timeout = timeout; + logger.info("Set read/write timeout to : " + timeout); + + } + + public int readData(byte[] dataRead, int nchar) throws IOException { + InputStream input; + input = getSocket().getInputStream(); + int nread = 0; + int startTime = (int) (new Date().getTime()); + do { + if (timeout == -1 || input.available() != 0) { + nread += input.read(dataRead, nread, nchar - nread); + startTime = (int) (new Date().getTime()); + } else { + int nowTime = (int) (new Date().getTime()); + if ((nowTime - startTime) > timeout) + break; + } + } while (nread != nchar); + return nread; + } + + /** + * Method sendMsg + * + * @param msg + * a COPSMsg + * + * @throws IOException + * @throws COPSException + * + */ + public void sendMsg(COPSMsg msg) throws IOException, COPSException { + logger.debug("sendMsg({})==>{}", getSocket(), msg); + msg.checkSanity(); + msg.writeData(getSocket()); + } + + /** + * Method receiveMessage + * + * @return a COPSMsg + * + * @throws IOException + * @throws COPSException + * + */ + public COPSMsg receiveMessage() throws IOException, COPSException { + int nread = 0; + byte[] hBuf = new byte[8]; + + logger.debug("receiveMessage({})", getSocket()); + + nread = readData(hBuf, 8); + + if (nread == 0) { + throw new COPSException("Error reading connection"); + } + + if (nread != 8) { + throw new COPSException("Bad COPS message"); + } + + COPSHeader hdr = new COPSHeader(hBuf); + int dataLen = hdr.getMsgLength() - hdr.getHdrLength(); + logger.debug("COPS Msg length :[" + dataLen + "]\n"); + byte[] buf = new byte[dataLen + 1]; + nread = 0; + + nread = readData(buf, dataLen); + buf[dataLen] = (byte) '\0'; + logger.debug("Data read length:[" + nread + "]\n"); + + if (nread != dataLen) { + throw new COPSException("Bad COPS message"); + } + COPSMsgParser prser = new COPSMsgParser(); + COPSMsg msg = prser.parse(hdr, buf); + return msg; + } + + /** + * @return the dataBuffer + */ + public ByteBuffer getDataBuffer() { + return dataBuffer; + } + + /** + * @param dataBuffer + * the dataBuffer to set + */ + public void setDataBuffer(ByteBuffer dataBuffer) { + this.dataBuffer = dataBuffer; + } + + /** + * @return the socket + */ + public Socket getSocket() { + return socket; + } + + /** + * @param socket + * the socket to set + */ + public void setSocket(Socket socket) { + this.socket = socket; + } + + /** + * @return the timeout + */ + public int getTimeout() { + return timeout; + } + + /** + * @param timeout + * the timeout to set + */ + public void setTimeout(int timeout) { + this.timeout = timeout; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/objects/MMVersionInfo.java b/packetcable-driver/src/main/java/org/pcmm/objects/MMVersionInfo.java new file mode 100644 index 0000000..4fa90a5 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/objects/MMVersionInfo.java @@ -0,0 +1,69 @@ +/** + @header@ + */ +package org.pcmm.objects; + +import org.pcmm.base.impl.PCMMBaseObject; + +/** + * + * PCMM MM version info Object + * + */ +public class MMVersionInfo extends PCMMBaseObject { + + private short majorVersionNB; + private short minorVersionNB; + public static final short DEFAULT_MAJOR_VERSION_INFO = (short) 5; + public static final short DEFAULT_MINOR_VERSION_INFO = (short) 0; + + public MMVersionInfo() { + this(DEFAULT_MAJOR_VERSION_INFO, DEFAULT_MINOR_VERSION_INFO); + } + + public MMVersionInfo(short majorVersionNB, short minorVersionNB) { + super((short) 8, (byte) 1, (byte) 16); + setShort(this.majorVersionNB = majorVersionNB, (short) 0); + setShort(this.minorVersionNB = minorVersionNB, (short) 2); + } + + /** + * Parse data and create COPSHandle object + */ + public MMVersionInfo(byte[] dataPtr) { + super(dataPtr); + majorVersionNB = getShort((short) 0); + minorVersionNB = getShort((short) 2); + } + + /** + * @return the majorVersionNB + */ + public short getMajorVersionNB() { + return majorVersionNB; + } + + /** + * @param majorVersionNB + * the majorVersionNB to set + */ + public void setMajorVersionNB(short majorVersionNB) { + this.majorVersionNB = majorVersionNB; + } + + /** + * @return the minorVersionNB + */ + public short getMinorVersionNB() { + return minorVersionNB; + } + + /** + * @param minorVersionNB + * the minorVersionNB to set + */ + public void setMinorVersionNB(short minorVersionNB) { + this.minorVersionNB = minorVersionNB; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/objects/PCMMIDHolder.java b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMIDHolder.java new file mode 100644 index 0000000..ce35dee --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMIDHolder.java @@ -0,0 +1,60 @@ +/** + @header@ + */ +package org.pcmm.objects; + +/** + * this class holds and maps flow ID to PCMM gate ID and Transaction ID + * + */ +public class PCMMIDHolder extends PCMMResource { + + /** + * flow id. + */ + private int flowID; + /** + * gate id. + */ + private int gateID; + /** + * transaction id. + */ + private short transactionID; + + public PCMMIDHolder(int flowID, int gateID, short transactionID) { + this.flowID = flowID; + this.gateID = gateID; + this.transactionID = transactionID; + + } + + public PCMMIDHolder() { + + } + + public int getFlowID() { + return flowID; + } + + public void setFlowID(int flowID) { + this.flowID = flowID; + } + + public int getGateID() { + return gateID; + } + + public void setGateID(int gateID) { + this.gateID = gateID; + } + + public short getTransactionID() { + return transactionID; + } + + public void setTransactionID(short transactionID) { + this.transactionID = transactionID; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResource.java b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResource.java new file mode 100644 index 0000000..5fc7966 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResource.java @@ -0,0 +1,15 @@ +/** + @header@ + */ +package org.pcmm.objects; + +/** + * + * This class is a holder for PCMM objects. This class is intended to be + * sub-classed + + * + */ +public class PCMMResource { + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResourceSet.java b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResourceSet.java new file mode 100644 index 0000000..a401fe8 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResourceSet.java @@ -0,0 +1,55 @@ +/** + @header@ + */ +package org.pcmm.objects; + +import java.util.HashMap; +import java.util.Map; + +/** + * This stores and handles the PCMM resources. + * + */ +public class PCMMResourceSet { + + private Map> mapper; + + private static PCMMResourceSet instance; + + private PCMMResourceSet() { + mapper = new HashMap>(); + } + + public static PCMMResourceSet getInstance() { + if (instance == null) + instance = new PCMMResourceSet(); + return instance; + } + + /** + * adds a new mapping + * + * @param key + * to be used for identifying mapped structure + * @return resource mapper + */ + @SuppressWarnings("unchecked") + public PCMMResourcesMapper getMappedResources( + Object key) { + return (PCMMResourcesMapper) mapper.get(key); + } + + public void mapResources(Object key, + PCMMResourcesMapper resources) { + mapper.put(key, resources); + } + + public void removeMapping(Object key) { + mapper.remove(key); + } + + public void removeAllMappings() { + mapper.clear(); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResourcesMapper.java b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResourcesMapper.java new file mode 100644 index 0000000..69468fd --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/objects/PCMMResourcesMapper.java @@ -0,0 +1,39 @@ +/** + @header@ + */ +package org.pcmm.objects; + +/** + * + * Resources mapper used to associate a key to a set of values + */ +public class PCMMResourcesMapper { + + private M key; + + private T value; + + public PCMMResourcesMapper() { + } + + public PCMMResourcesMapper(M key, T value) { + this.key = key; + this.value = value; + } + + public M getKey() { + return key; + } + + public void setKey(M key) { + this.key = key; + } + + public T getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/objects/SyncOptions.java b/packetcable-driver/src/main/java/org/pcmm/objects/SyncOptions.java new file mode 100644 index 0000000..409862b --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/objects/SyncOptions.java @@ -0,0 +1,73 @@ +/** + @header@ + */ +package org.pcmm.objects; + +import org.pcmm.base.impl.PCMMBaseObject; + +/** + * + * PCMM SyncOptions object + * + */ +public class SyncOptions extends PCMMBaseObject { + + private byte synchType; + + private byte reportType; + + public static final byte STANDARD_REPORT_DATA = (byte) 0; + public static final byte COMPLETE_GATE_DATA = (byte) 1; + public static final byte FULL_SYNCHRONIZATION = (byte) 0; + public static final byte INCREMENTAL_SYNCHRONIZATION = (byte) 1; + + public SyncOptions() { + this(STANDARD_REPORT_DATA, FULL_SYNCHRONIZATION); + } + + public SyncOptions(byte reportType, byte synchType) { + super((short) 8, (byte) 1, (byte) 18); + setByte(this.reportType = reportType, (short) 4); + setByte(this.synchType = synchType, (short) 6); + } + + /** + * Parse data and create COPSHandle object + */ + public SyncOptions(byte[] dataPtr) { + super(dataPtr); + reportType = getByte((short) 4); + synchType = getByte((short) 6); + } + + /** + * @return the synchType + */ + public byte getSynchType() { + return synchType; + } + + /** + * @param synchType + * the synchType to set + */ + public void setSynchType(byte synchType) { + this.synchType = synchType; + } + + /** + * @return the reportType + */ + public byte getReportType() { + return reportType; + } + + /** + * @param reportType + * the reportType to set + */ + public void setReportType(byte reportType) { + this.reportType = reportType; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/ICMTS.java b/packetcable-driver/src/main/java/org/pcmm/rcd/ICMTS.java new file mode 100644 index 0000000..580ea2c --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/ICMTS.java @@ -0,0 +1,47 @@ +/** + @header@ + */ + +package org.pcmm.rcd; + +/** + *

+ * In describing the role of the CMTS network element, it is important to + * consider the relation among DOCSIS, PacketCable 1.x and PacketCable + * Multimedia functionality. While each of these suites of specifications + * addresses a specific set of functional requirements, each has also been + * defined in such a way that corresponding implementations may be constructed + * in a modular manner; either PacketCable 1.x or PacketCable Multimedia Gate + * Control may be layered on top of a DOCSIS 1.1 or greater CMTS foundation, + * with the option of adding additional, complementary functionality as business + * indicates. Further, it should be emphasized that it is a significant asset of + * the PacketCable architecture that both telephony and Multimedia variants + * employ considerable architectural similarity, leading to potential reuse in + * the underlying Gate management models. + *

+ *

+ * The PacketCable Multimedia CMTS is a generalized version of the PacketCable + * 1.x CMTS that has been defined in order to deliver telephony services in + * PacketCable 1.x networks. The CMTS is responsible for fulfilling requests for + * QoS that are received from one or more Policy Servers. It performs this + * function by installing Gates, which are similar to the Gates defined in [14]; + * Gates allow the subscriber's cable modem to request network resources from + * the CMTS through the creation of dynamic DOCSIS flows with guaranteed levels + * of QoS. The CMTS also sends Event Messages detailing actual usage of QoS + * resources to the Record Keeping Server. + *

+ *

+ * The CMTS acts as a server (PS should send OPN message to CMTS to initiate + * communication), and acts as a client for the rest of the exchange process. + *

+ * + * + */ +public interface ICMTS extends IPCMMServer { + + // generates a GateID and assigns it to the IPCMMGate. + + static final short DEFAULT_R_TYPE = (short) 0x08; + static final short DEFAULT_M_TYPE = (short) 0; + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMClient.java b/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMClient.java new file mode 100644 index 0000000..d1b1341 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMClient.java @@ -0,0 +1,97 @@ +/** + @header@ + */ + +package org.pcmm.rcd; + +import java.net.InetAddress; + +import org.umu.cops.stack.COPSMsg; + +/** + *

+ * This is a Client Type 1, which represents existing "legacy" endpoints (e.g., + * PC applications, gaming consoles) that lack specific QoS awareness or + * signaling capabilities. This client has no awareness of DOCSIS, CableHome, or + * PacketCable messaging, and hence no related requirements can be placed upon + * it. Client Type 1 communicates with an Application Manager to request + * service, and does not (cannot) request QoS resources directly from the MSO + * access network. + *

+ * + * + */ +public interface IPCMMClient { + + /** + * PCMM client-type + */ + static final short CLIENT_TYPE = (short) 0x800A; + + /** + * sends a message to the server. + * + * @param requestMessage + * request message. + */ + void sendRequest(COPSMsg requestMessage); + + /** + * Reads message from server + * + * @return COPS message + */ + COPSMsg readMessage(); + + /** + * tries to connect to the server. + * + * @param address + * server address + * @param port + * server port + * @return connection state + */ + boolean tryConnect(String address, int port); + + /** + * tries to connect to the server. + * + * @param address + * server address + * @param port + * server port + * @return connection state + */ + boolean tryConnect(InetAddress address, int port); + + /** + * disconnects from server. + * + * @return disconnection status. + */ + boolean disconnect(); + + /** + * + * @return whether the client is connected to the server of not. + */ + boolean isConnected(); + + /** + * gets the client handle + * + * @return client handle + */ + String getClientHandle(); + + /** + * + * sets the client handle + * + * @param handle + * cleint hanlde + */ + void setClientHandle(String handle); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMPolicyServer.java b/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMPolicyServer.java new file mode 100644 index 0000000..b23c83e --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMPolicyServer.java @@ -0,0 +1,222 @@ +/** + @header@ + */ + +package org.pcmm.rcd; + +import java.net.InetAddress; + +import org.pcmm.objects.MMVersionInfo; +import org.pcmm.state.IStateful; + +/** + * PKT-SP-MM-I05-091029 PacketCableTM Specification + *

+ * As discussed in RFC 2753 [11], the policy management framework underlying + * PacketCable Multimedia is based on the work of the IETF's Resource Allocation + * Protocol (RAP) working group. Since the Policy Server is situated between the + * Application Manager and the CMTS, it simultaneously plays a dual role as a + * "proxy" for AM-initiated session requests and as a "sentry" for defining and + * enforcing Resource Control Domain policy. As described in [11] and in keeping + * with the PacketCable 1.x DQoS model, the Policy Server serves as Policy + * Decision Point (PDP) in relation to the CMTS in that the Policy Server + * implements MSO-defined authorization and resource-management procedures. + * Conversely, the Policy Server assumes the role of Policy Enforcement Point + * (PEP) in relation to the Application Manager as it proxies Gate Control + * messages to and from the CMTS element. To revisit the interaction scenario, + * the Application Manager issues policy requests to the Policy Server. The + * Policy Server acting as a "sentry" for these requests, and applies a set of + * policy rules that have been pre-provisioned by the MSO. Upon passing the + * checks, the Policy Server then acts as a "proxy" with respect to the + * Application Manager and the CMTS, forwarding the policy request and returning + * any associated response. Each policy request transaction must be processed + * individually. Policy decisions may be based on a number of factors, such as: + *

    + *
  • Parameters associated with the request and the status of available + * resources
  • + *
  • Identity of the particular client and associated profile information
  • + *
  • Application parameters
  • + *
  • Security considerations
  • + *
  • Time-of-day
  • + *
+ * The primary functions of the Policy Server include: + *
    + *
  • A policy decision request mechanism, invoked by Application Managers
  • + *
  • A policy decision request 'policing' mechanism, enforcing installed + * Policy Rules
  • + *
  • A policy decision delivery mechanism, used to install policy decisions on + * the CMTS
  • + *
  • A mechanism to allow for the proxying of QoS management messages to the + * CMTS on behalf of the Application Manager
  • + *
  • An event recording interface to a Record Keeping Server that is used to + * log policy requests, which may in turn be correlated with network resource + * usage records
  • · + *
+ * Since the Policy Server functions as a proxy between the AM and CMTS elements + * (with complementary client and server interfaces) some MSOs may elect to + * deploy multiple layers of Policy Servers and to delegate certain policy + * decisions among these servers in order to satisfy requirements associated + * with scalability and fault-tolerance. + *

+ *

+ * Stateful & Stateless Policy Servers There are two basic classes of + * Policy Servers – Stateful and Stateless. A Stateless Policy Server is a + * slight misnomer since it does maintain enough state to map Application + * Manager requests to the proper CMTS and maintain COPS session state, while a + * pure Stateless Policy Server maintains no state on any of the media sessions. + * Stateful Policy Servers come in several varieties – some participate in + * admission control and thus monitor the QoS attributes of active media + * sessions, some leave QoS and admission control to the CMTS but monitor + * time-based or volume-based service requests from the Application Manager, and + * some Policy Servers are somewhere between these extremes. The reason there is + * a variety of Policy Server types is that there is a variety of environments + * that operators are trying to support. For example, some operators may wish to + * support PacketCable Multimedia over the same CMTSs that they use for + * PacketCable telephony, and they may want a single CMS/Policy Server that has + * a more global view of the network resources being used. On the other hand, + * some operators may wish to run a PacketCable Multimedia- only environment, or + * they may utilize simpler CMTS-driven mechanisms for partitioning PacketCable + * Multimedia and telephony resources. These simpler configurations have more + * modest requirements on the amount of state that a Policy Server maintains. + * Policy Server state requirements can also be driven by the level of trust + * between the Policy Server and Application Manager; a Stateful Policy Server + * can more readily police Application Manager session control behavior than can + * a Stateless Policy Server. So a Stateful Policy Server may be more + * appropriate for operators supporting third party Application Managers. Other + * operators may rely on economics to enforce their trust relationships with + * Application Managers, or they may control the Application Managers + * themselves. In such cases a Stateless Policy Server may be more appropriate. + * Since it is impossible to categorize all the various components of media + * session and network QoS state that a Policy Server is maintaining, the + * protocol is designed to be independent of this complexity. A Stateful Policy + * Server gleans PacketCable Multimedia media session information from the + * Application Manager requests it proxies; any other information it requires is + * gathered via mechanisms that are outside the scope of this specification. The + * CMTS and the Application Manager make no distinction as to the type of Policy + * Server to which they are connected, and the protocol is designed in such a + * manner that the type of Policy Server is transparent to the end point. The + * type of Policy Server is only of importance to the operator. Since some types + * of Policy Servers attempt to assist with admission control and may have a + * larger view of the network and its resources, additional state + * synchronization issues may arise in design in a network which contains more + * than one of these types of Policy Servers. It is the responsibility of the + * operator to ensure that the efforts of these Policy Servers are not + * undermined by a network that includes other autonomous Policy Servers. + *

+ *

+ * Modification of Requests and Responses by Policy Servers Although + * nominally a part of the Resource Control Domain, the Policy Server can be an + * intermediary between the Service and the Resource Control Domains, in + * addition to its normal role of implementing MSO-defined authorization and + * resource management procedures. In either of these capacities it may modify + * the incoming request before forwarding it to the CMTS. In acting as an + * intermediary between the SCD and RCD, the Policy Server may translate fields + * from formats or scales used in the SCD into formats or scales used in the + * RCD. For example, the Policy Server may modify the "priority" of a request + * coming from an Application Manager (especially important to do for an AM + * outside of the MSO network) so that this priority field uses a consistent + * scale throughout the operator's RCD. In its capacity as an intermediary, the + * Policy Server may use bidirectional translation – in other words, it should + * translate requests from the AM to the CMTS and "untranslate" the responses + * from the CMTS to the AM. This capability can be supported by stateful policy + * servers by remembering the original request, and it can be supported by + * stateless Policy Servers if the translation function is invertible. + * Modification of certain objects, specifically the Classifier and Traffic + * Profile objects, may cause operational problems in the originating AM. As + * such, these objects MUST NOT be modified by the policy server. Aside from + * these exceptions, all other objects may be policed and modified at the PS's + * discretion based on provisioned policy rules. + *

+ * + */ +public interface IPCMMPolicyServer extends IPCMMServer, IStateful { + + /** + * establishes COPS connection with the CMTS + * + * @param host + * : remote host name or ip address + * @return connected socket. + */ + IPSCMTSClient requestCMTSConnection(String host); + + /** + * establishes COPS connection with the CMTS + * + * @param host + * : remote ip address‚ + * @return connected socket. + */ + IPSCMTSClient requestCMTSConnection(InetAddress host); + + /** + *

+ * In the PacketCable model, the CMTS (PEP) is the one that listens on the + * assigned port 3918, and it is the Policy Server that MUST initiate the + * TCP connection to the CMTS, thus we implement the IPCMMClient interface. + *

+ */ + public static interface IPSCMTSClient extends IPCMMClient { + + /** + * + * @return Classifier Id. + */ + short getClassifierId(); + + /** + * + * @return the transaction Id. + */ + short getTransactionId(); + + /** + * Gate id transmitted by the CMTS to the PS. + * + * @return the Gate Id. + */ + int getGateId(); + + /** + * initiates a Gate-Set with the CMTS + * + * @return + */ + boolean gateSet(); + + /** + * initiates a Gate-Info with the CMTS + * + * @return + */ + boolean gateInfo(); + + /** + * initiates a Gate-Delete with the CMTS + * + * @return + */ + boolean gateDelete(); + + /** + * sends synch request + * + * @return + */ + boolean gateSynchronize(); + + /** + * Sets the value of the multi-media version info. + * + * @param MM + * version info + */ + void setVersionInfo(MMVersionInfo vInfo); + + /** + * + * @return MM version info + */ + MMVersionInfo getVersionInfo(); + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMServer.java b/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMServer.java new file mode 100644 index 0000000..794af06 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/IPCMMServer.java @@ -0,0 +1,91 @@ +/** + @header@ + */ + + +package org.pcmm.rcd; + +import org.pcmm.concurrent.IWorker; +import org.pcmm.state.IStateful; + +/** + *

+ * As discussed in RFC 2753 [11], the policy management framework underlying + * PacketCable Multimedia is based on the work of the IETF's Resource Allocation + * Protocol (RAP) working group. Since the Policy Server is situated between the + * Application Manager and the CMTS, it simultaneously plays a dual role as a + * "proxy" for AM-initiated session requests and as a "sentry" for defining and + * enforcing Resource Control Domain policy. + *

+ *

+ * As described in [11] and in keeping with the PacketCable 1.x DQoS model, the + * Policy Server serves as Policy Decision Point (PDP) in relation to the CMTS + * resource-management procedures. Conversely, the Policy Server assumes the + * role of Policy Enforcement Point (PEP) in relation to the Application Manager + * as it proxies Gate Control messages to and from the CMTS element. + *

+ *

+ * To revisit the interaction scenario, the Application Manager issues policy + * requests to the Policy Server. The Policy Server acting as a "sentry" for + * these requests, and applies a set of policy rules that have been + * pre-provisioned by the MSO. Upon passing the checks, the Policy Server then + * acts as a "proxy" with respect to the Application Manager and the CMTS, + * forwarding the policy request and returning any associated response. Each + * policy request transaction must be processed individually. + *

+ *

+ * Policy decisions may be based on a number of factors, such as: + *

    + *
  • Parameters associated with the request and the status of available + * resources
  • + *
  • Identity of the particular client and associated profile information
  • + *
  • Application parameters
  • + *
  • Security considerations
  • + *
  • Time-of-day
  • + *
+ * The primary functions of the Policy Server include: + *
    + *
  • A policy decision request mechanism, invoked by Application Managers
  • + *
  • A policy decision request 'policing' mechanism, enforcing installed + * Policy Rules
  • + *
  • A policy decision delivery mechanism, used to install policy decisions on + * the CMTS
  • + *
  • A mechanism to allow for the proxying of QoS management messages to the + * CMTS on behalf of the Application Manager
  • + *
  • An event recording interface to a Record Keeping Server that is used to + * log policy requests, which may in turn be correlated with network resource + * usage records
  • + *
+ *

+ * Since the Policy Server functions as a proxy between the AM and CMTS elements + * (with complementary client and server interfaces) some MSOs may elect to + * deploy multiple layers of Policy Servers and to delegate certain policy + * decisions among these servers in order to satisfy requirements associated + * with scalability and fault-tolerance. + *

+ *

+ * + * + */ +public interface IPCMMServer extends IStateful { + + /** + * + */ + void startServer(); + + /** + * + */ + void stopServer(); + + /** + * When a client connects to the server, a handler is needed to manage the + * exchange of the messages between this client and the server. + * + * + */ + public static interface IPCMMClientHandler extends IWorker, IPCMMClient { + + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/impl/AbstractPCMMClient.java b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/AbstractPCMMClient.java new file mode 100644 index 0000000..6a29743 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/AbstractPCMMClient.java @@ -0,0 +1,176 @@ +/** + @header@ + */ +package org.pcmm.rcd.impl; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import org.pcmm.nio.PCMMChannel; +// import org.junit.Assert; +import org.pcmm.objects.MMVersionInfo; +import org.pcmm.rcd.IPCMMClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.umu.cops.stack.COPSMsg; + +/** + * + * default implementation for {@link IPCMMClient} + * + * + */ +public class AbstractPCMMClient implements IPCMMClient { + + protected Logger logger = LoggerFactory.getLogger(AbstractPCMMClient.class); + /** + * socket used to communicated with server. + */ + private Socket socket; + + private String clientHanlde; + + private MMVersionInfo versionInfo; + + private PCMMChannel channel; + + public AbstractPCMMClient() { + } + + /* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMClient#sendRequest(pcmm.messages.IMessage) + */ + public void sendRequest(COPSMsg requestMessage) { + try { + channel.sendMsg(requestMessage); + } catch (Exception e) { + logger.error(e.getMessage(), getSocket()); + } + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.rcd.IPCMMClient#readMessage() + */ + public COPSMsg readMessage() { + try { + COPSMsg recvdMsg = channel.receiveMessage(); + // logger.debug("received message : " + recvdMsg.getHeader()); + return recvdMsg; + } catch (Exception e) { + logger.error(e.getMessage(), getSocket()); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMClient#tryConnect(java.lang.String, int) + */ + public boolean tryConnect(String address, int port) { + try { + InetAddress addr = InetAddress.getByName(address); + tryConnect(addr, port); + } catch (UnknownHostException e) { + logger.error(e.getMessage()); + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMClient#tryConnect(java.net.InetAddress, int) + */ + public boolean tryConnect(InetAddress address, int port) { + try { + setSocket(new Socket(address, port)); + } catch (IOException e) { + logger.error(e.getMessage()); + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMClient#disconnect() + */ + public boolean disconnect() { + if (isConnected()) { + try { + socket.close(); + channel = null; + } catch (IOException e) { + logger.error(e.getMessage()); + } + } + return true; + } + + /** + * @return the socket + */ + public Socket getSocket() { + return socket; + } + + public PCMMChannel getChannel() { + return channel; + } + + /** + * @param socket + * the socket to set + */ + public void setSocket(Socket socket) { + this.socket = socket; + if (this.socket != null + && (this.channel == null || !this.channel.getSocket().equals( + this.socket))) + channel = new PCMMChannel(this.socket); + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.rcd.IPCMMClient#isConnected() + */ + public boolean isConnected() { + return socket != null && socket.isConnected(); + } + + /** + * @return the versionInfo + */ + public MMVersionInfo getVersionInfo() { + return versionInfo; + } + + /** + * @param versionInfo + * the versionInfo to set + */ + public void setVersionInfo(MMVersionInfo versionInfo) { + this.versionInfo = versionInfo; + } + + @Override + public String getClientHandle() { + return clientHanlde; + } + + @Override + public void setClientHandle(String handle) { + this.clientHanlde = handle; + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/impl/AbstractPCMMServer.java b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/AbstractPCMMServer.java new file mode 100644 index 0000000..bac4979 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/AbstractPCMMServer.java @@ -0,0 +1,214 @@ +/** + @header@ + */ +package org.pcmm.rcd.impl; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.Executors; + +import org.pcmm.PCMMConstants; +import org.pcmm.PCMMProperties; +import org.pcmm.concurrent.IWorkerPool; +import org.pcmm.concurrent.impl.WorkerPool; +// import org.junit.Assert; +import org.pcmm.messages.impl.MessageFactory; +import org.pcmm.rcd.IPCMMServer; +import org.pcmm.state.IState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSMsg; + +/* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMServer + */ +public abstract class AbstractPCMMServer implements IPCMMServer { + protected Logger logger; + /* + * A ServerSocket to accept messages ( OPN requests) + */ + private ServerSocket serverSocket; + + private Socket stopSocket; + + private volatile boolean keepAlive; + /* + * + */ + private int port; + + IWorkerPool pool; + + protected AbstractPCMMServer() { + this(PCMMProperties.get(PCMMConstants.PCMM_PORT, Integer.class)); + } + + protected AbstractPCMMServer(int port) { + // XXX - Assert.assertTrue(port >= 0 && port <= 65535); + this.port = port; + keepAlive = true; + logger = LoggerFactory.getLogger(getClass().getName()); + int poolSize = PCMMProperties.get(PCMMConstants.PS_POOL_SIZE, Integer.class); + pool = new WorkerPool(poolSize); + } + + /* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMServer#startServer() + */ + public void startServer() { + if (serverSocket != null) + return; + try { + serverSocket = new ServerSocket(port); + logger.info("Server started and listening on port :" + port); + } catch (IOException e) { + logger.error(e.getMessage()); + } + // execute this in a single thread executor + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + while (keepAlive) { + try { + Socket socket = serverSocket.accept(); + logger.info("Accepted a new connection from :" + socket.getInetAddress().getHostAddress() + ":" + socket.getPort()); + if (keepAlive) { + pool.schedule(getPCMMClientHandler(socket)); + logger.info("Handler attached tp : " + socket.getInetAddress().getHostAddress() + ":" + socket.getPort()); + } else { + logger.info("connection to be closed : " + socket.getInetAddress().getHostAddress() + ":" + socket.getPort()); + socket.close(); + } + } catch (IOException e) { + logger.error(e.getMessage()); + } + } + try { + if (stopSocket != null && stopSocket.isConnected()) { + logger.info("Cleaning up"); + stopSocket.close(); + } + if (serverSocket != null && serverSocket.isBound()) { + logger.info("Server about to stop"); + serverSocket.close(); + logger.info("Server stopped"); + } + } catch (IOException e) { + logger.error(e.getMessage()); + } + } + }); + } + + /** + * This client is used to handle requests from within the Application + * Manager + * + * @param socket + * @return client handler + */ + protected abstract IPCMMClientHandler getPCMMClientHandler(Socket socket); + + /* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMServer#stopServer() + */ + public void stopServer() { + // set to stop + keepAlive = false; + try { + if (serverSocket != null) { + stopSocket = new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()); + logger.info("STOP socket created and attached"); + } + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + + /* + * (non-Javadoc) + * + * @see pcmm.state.IStateful#recordState() + */ + public void recordState() { + + } + + /* + * (non-Javadoc) + * + * @see pcmm.state.IStateful#getRecoredState() + */ + public IState getRecoredState() { + return null; + } + + /** + * @return the serverSocket + */ + public ServerSocket getServerSocket() { + return serverSocket; + } + + /** + * @param serverSocket + * the serverSocket to set + */ + public void setServerSocket(ServerSocket serverSocket) { + this.serverSocket = serverSocket; + } + + /** + * @return the port + */ + public int getPort() { + return port; + } + + /** + * @param port + * the port to set + */ + public void setPort(int port) { + this.port = port; + } + + /* + * (non-Javadoc) + * + * @see pcmm.rcd.IPCMMServer.IPCMMClientHandler + */ + public abstract class AbstractPCMMClientHandler extends AbstractPCMMClient + implements IPCMMClientHandler { + + protected boolean sendCCMessage = false; + + public AbstractPCMMClientHandler(Socket socket) { + super(); + setSocket(socket); + } + + @Override + public boolean disconnect() { + // XXX send CC message + sendCCMessage = true; + /* + * is this really needed ? + */ + // if (getSocket() != null) + // handlersPool.remove(getSocket()); + COPSMsg message = MessageFactory.getInstance().create(COPSHeader.COPS_OP_CC); + sendRequest(message); + return super.disconnect(); + } + + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/impl/CMTS.java b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/CMTS.java new file mode 100644 index 0000000..fa89754 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/CMTS.java @@ -0,0 +1,355 @@ +/** + @header@ + */ +package org.pcmm.rcd.impl; + +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Properties; +import java.util.Vector; +import java.util.concurrent.Callable; + +import org.pcmm.gates.IPCMMGate; +import org.pcmm.gates.ITransactionID; +import org.pcmm.gates.impl.PCMMGateReq; +import org.pcmm.messages.impl.MessageFactory; +import org.pcmm.rcd.ICMTS; +import org.umu.cops.prpep.COPSPepConnection; +import org.umu.cops.prpep.COPSPepDataProcess; +import org.umu.cops.prpep.COPSPepException; +import org.umu.cops.prpep.COPSPepReqStateMan; +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPrObjBase; +import org.umu.cops.stack.COPSReqMsg; + +/** + * + */ +public class CMTS extends AbstractPCMMServer implements ICMTS { + + public CMTS() { + super(); + } + + @Override + protected IPCMMClientHandler getPCMMClientHandler(final Socket socket) { + + return new AbstractPCMMClientHandler(socket) { + + private String handle; + + public void run() { + try { + // send OPN message + // set the major version info and minor version info to + // default (5,0) + logger.info("Send OPN message to the PS"); + sendRequest(MessageFactory.getInstance().create(COPSHeader.COPS_OP_OPN, new Properties())); + // wait for CAT + COPSMsg recvMsg = readMessage(); + + if (recvMsg.getHeader().isAClientClose()) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) recvMsg; + logger.info("PS requested Client-Close" + cMsg.getError().getDescription()); + // send a CC message and close the socket + disconnect(); + return; + } + if (recvMsg.getHeader().isAClientAccept()) { + logger.info("received Client-Accept from PS"); + COPSClientAcceptMsg cMsg = (COPSClientAcceptMsg) recvMsg; + // Support + if (cMsg.getIntegrity() != null) { + throw new COPSPepException("Unsupported object (Integrity)"); + } + + // Mandatory KATimer + COPSKATimer kt = cMsg.getKATimer(); + if (kt == null) + throw new COPSPepException("Mandatory COPS object missing (KA Timer)"); + short kaTimeVal = kt.getTimerVal(); + + // ACTimer + COPSAcctTimer at = cMsg.getAcctTimer(); + short acctTimer = 0; + if (at != null) + acctTimer = at.getTimerVal(); + + logger.info("Send a REQ message to the PS"); + { + Properties prop = new Properties(); + COPSMsg reqMsg = MessageFactory.getInstance().create(COPSHeader.COPS_OP_REQ, prop); + handle = ((COPSReqMsg) reqMsg).getClientHandle().getId().str(); + sendRequest(reqMsg); + } + // Create the connection manager + PCMMCmtsConnection conn = new PCMMCmtsConnection(CLIENT_TYPE, socket); + // pcmm specific handler + // conn.addReqStateMgr(handle, new + // PCMMPSReqStateMan(CLIENT_TYPE, handle)); + conn.addRequestState(handle, new CmtsDataProcessor()); + conn.setKaTimer(kaTimeVal); + conn.setAcctTimer(acctTimer); + logger.info(getClass().getName() + " Thread(conn).start"); + new Thread(conn).start(); + } else { + // messages of other types are not expected + throw new COPSPepException("Message not expected. Closing connection for " + socket.toString()); + } + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + + @Override + public void task(Callable c) { + // TODO Auto-generated method stub + + } + + @Override + public void shouldWait(int t) { + // TODO Auto-generated method stub + + } + + @Override + public void done() { + // TODO Auto-generated method stub + + } + + }; + } + + /* public */class PCMMCmtsConnection extends COPSPepConnection { + + public PCMMCmtsConnection(short clientType, Socket sock) { + super(clientType, sock); + } + + public COPSPepReqStateMan addRequestState(String clientHandle, COPSPepDataProcess process) + throws COPSException, COPSPepException { + return super.addRequestState(clientHandle, process); + } + + // public void addReqStateMgr(String hanlde, COPSPepReqStateMan r) { + // // map < String(COPSHandle), COPSPepReqStateMan>; + // getReqStateMans().put(hanlde, r); + // } + } + + @SuppressWarnings("rawtypes") + class PCMMPSReqStateMan extends COPSPepReqStateMan { + + public PCMMPSReqStateMan(short clientType, String clientHandle) { + super(clientType, clientHandle); + _process = new CmtsDataProcessor(); + + } + + @Override + protected void processDecision(COPSDecisionMsg dMsg) + throws COPSPepException { + + // COPSHandle handle = dMsg.getClientHandle(); + Hashtable decisions = dMsg.getDecisions(); + + Hashtable removeDecs = new Hashtable(10); + Hashtable installDecs = new Hashtable(10); + Hashtable errorDecs = new Hashtable(10); + for (Enumeration e = decisions.keys(); e.hasMoreElements();) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) decisions.get(context); + Enumeration ee = v.elements(); + COPSDecision cmddecision = (COPSDecision) ee.nextElement(); + + // cmddecision --> we must check whether it is an error! + + if (cmddecision.isInstallDecision()) { + String prid = new String(); + for (; ee.hasMoreElements();) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + COPSPrObjBase obj = new COPSPrObjBase(decision.getData().getData()); + switch (obj.getSNum()) { + // TODO when there is install request only the PR_PRID + // is git but the ClientSI object containing the PR_EPD + // is null??? this is why the tests fail and so I set + // the assertion to NOT true.... + case COPSPrObjBase.PR_PRID: + prid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + installDecs.put(prid, obj.getData().str()); + break; + default: + break; + } + } + } + if (cmddecision.isRemoveDecision()) { + String prid = new String(); + for (; ee.hasMoreElements();) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + COPSPrObjBase obj = new COPSPrObjBase(decision.getData().getData()); + switch (obj.getSNum()) { + case COPSPrObjBase.PR_PRID: + prid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + removeDecs.put(prid, obj.getData().str()); + break; + default: + break; + } + } + } + } + if (_process != null) { + // ** Apply decisions to the configuration + _process.setDecisions(this, removeDecs, installDecs, errorDecs); + _status = ST_DECS; + if (_process.isFailReport(this)) { + // COPSDebug.out(getClass().getName(),"Sending FAIL Report\n"); + _sender.sendFailReport(_process.getReportData(this)); + } else { + // COPSDebug.out(getClass().getName(),"Sending SUCCESS Report\n"); + _sender.sendSuccessReport(_process.getReportData(this)); + } + _status = ST_REPORT; + } + } + } + + @SuppressWarnings("rawtypes") + class CmtsDataProcessor extends COPSPepDataProcess { + + private Hashtable removeDecs; + private Hashtable installDecs; + private Hashtable errorDecs; + private COPSPepReqStateMan stateManager; + + public CmtsDataProcessor() { + setRemoveDecs(new Hashtable(10)); + setInstallDecs(new Hashtable(10)); + setErrorDecs(new Hashtable(10)); + } + + @SuppressWarnings("unchecked") + @Override + public void setDecisions(COPSPepReqStateMan man, Hashtable removeDecs, Hashtable installDecs, Hashtable errorDecs) { + setRemoveDecs(removeDecs); + setInstallDecs(installDecs); + setErrorDecs(errorDecs); + setStateManager(man); + } + + @Override + public boolean isFailReport(COPSPepReqStateMan man) { + return (errorDecs != null && errorDecs.size() > 0); + } + + @Override + public Hashtable getReportData(COPSPepReqStateMan man) { + if (isFailReport(man)) { + return errorDecs; + } else { + ITransactionID transactionID = null; + String key = null; + Hashtable siDataHashTable = new Hashtable(); + if (installDecs.size() > 0) { + String data = ""; + for (String k : installDecs.keySet()) { + data = installDecs.get(k); + break; + } + transactionID = new PCMMGateReq(new COPSData(data).getData()).getTransactionID(); + IPCMMGate responseGate = new PCMMGateReq(); + responseGate.setTransactionID(transactionID); + siDataHashTable.put(key, new String(responseGate.getData())); + } + return siDataHashTable; + } + } + + @Override + public Hashtable getClientData(COPSPepReqStateMan man) { + // TODO Auto-generated method stub + return new Hashtable(); + } + + @Override + public Hashtable getAcctData(COPSPepReqStateMan man) { + // TODO Auto-generated method stub + return new Hashtable(); + } + + @Override + public void notifyClosedConnection(COPSPepReqStateMan man, COPSError error) { + + } + + @Override + public void notifyNoKAliveReceived(COPSPepReqStateMan man) { + // TODO Auto-generated method stub + + } + + @Override + public void closeRequestState(COPSPepReqStateMan man) { + // TODO Auto-generated method stub + + } + + @Override + public void newRequestState(COPSPepReqStateMan man) { + // TODO Auto-generated method stub + + } + + public Hashtable getRemoveDecs() { + return removeDecs; + } + + public void setRemoveDecs(Hashtable removeDecs) { + this.removeDecs = removeDecs; + } + + public Hashtable getInstallDecs() { + return installDecs; + } + + public void setInstallDecs(Hashtable installDecs) { + this.installDecs = installDecs; + } + + public Hashtable getErrorDecs() { + return errorDecs; + } + + public void setErrorDecs(Hashtable errorDecs) { + this.errorDecs = errorDecs; + } + + public COPSPepReqStateMan getStateManager() { + return stateManager; + } + + public void setStateManager(COPSPepReqStateMan stateManager) { + this.stateManager = stateManager; + } + } +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/impl/PCMMPolicyServer.java b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/PCMMPolicyServer.java new file mode 100644 index 0000000..bd763eb --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/impl/PCMMPolicyServer.java @@ -0,0 +1,652 @@ +/** + * @header@ + */ +package org.pcmm.rcd.impl; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.Properties; + +import org.pcmm.PCMMConstants; +import org.pcmm.PCMMGlobalConfig; +import org.pcmm.PCMMProperties; +import org.pcmm.gates.IAMID; +import org.pcmm.gates.IClassifier; +import org.pcmm.gates.IExtendedClassifier; +import org.pcmm.gates.IGateID; +import org.pcmm.gates.IGateSpec; +import org.pcmm.gates.IGateSpec.DSCPTOS; +import org.pcmm.gates.IGateSpec.Direction; +import org.pcmm.gates.IPCMMError; +import org.pcmm.gates.IPCMMGate; +import org.pcmm.gates.ISubscriberID; +import org.pcmm.gates.ITrafficProfile; +import org.pcmm.gates.ITransactionID; +import org.pcmm.gates.impl.AMID; +import org.pcmm.gates.impl.BestEffortService; +import org.pcmm.gates.impl.Classifier; +import org.pcmm.gates.impl.ExtendedClassifier; +import org.pcmm.gates.impl.GateID; +import org.pcmm.gates.impl.GateSpec; +import org.pcmm.gates.impl.PCMMError; +import org.pcmm.gates.impl.PCMMGateReq; +import org.pcmm.gates.impl.SubscriberID; +import org.pcmm.gates.impl.TransactionID; +import org.pcmm.messages.IMessage.MessageProperties; +import org.pcmm.messages.impl.MessageFactory; +import org.pcmm.objects.MMVersionInfo; +import org.pcmm.rcd.IPCMMPolicyServer; +import org.pcmm.utils.PCMMException; +import org.umu.cops.prpdp.COPSPdpConnection; +import org.umu.cops.prpdp.COPSPdpDataProcess; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReqMsg; + +/** + * + * PCMM policy server + * + */ +public class PCMMPolicyServer extends AbstractPCMMServer implements + IPCMMPolicyServer { + /** + * since PCMMPolicyServer can connect to multiple CMTS (PEP) we need to + * manage each connection in a separate thread. + */ + + public PCMMPolicyServer() { + super(); + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.rcd.IPCMMPolicyServer#requestCMTSConnection(java.lang.String) + */ + public IPSCMTSClient requestCMTSConnection(String host) { + try { + InetAddress address = InetAddress.getByName(host); + return requestCMTSConnection(address); + } catch (UnknownHostException e) { + logger.error(e.getMessage()); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.pcmm.rcd.IPCMMPolicyServer#requestCMTSConnection(java.net.InetAddress + * ) + */ + public IPSCMTSClient requestCMTSConnection(InetAddress host) { + IPSCMTSClient client = new PSCMTSClient(); + try { + if (client.tryConnect(host, PCMMProperties.get(PCMMConstants.PCMM_PORT, Integer.class))) { + boolean endNegotiation = false; + while (!endNegotiation) { + logger.debug("waiting for OPN message from CMTS"); + COPSMsg opnMessage = client.readMessage(); + // Client-Close + if (opnMessage.getHeader().isAClientClose()) { + COPSError error = ((COPSClientCloseMsg) opnMessage).getError(); + logger.debug("CMTS requetsed Client-Close"); + throw new PCMMException(new PCMMError(error.getErrCode(), error.getErrSubCode())); + } else // Client-Open + if (opnMessage.getHeader().isAClientOpen()) { + logger.debug("OPN message received from CMTS"); + COPSClientOpenMsg opn = (COPSClientOpenMsg) opnMessage; + if (opn.getClientSI() == null) + throw new COPSException("CMTS shoud have sent MM version info in Client-Open message"); + else { + // set the version info + MMVersionInfo vInfo = new MMVersionInfo(opn.getClientSI().getData().getData()); + client.setVersionInfo(vInfo); + logger.debug("CMTS sent MMVersion info : major:" + vInfo.getMajorVersionNB() + " minor:" + vInfo.getMinorVersionNB()); // + if (client.getVersionInfo().getMajorVersionNB() == client.getVersionInfo().getMinorVersionNB()) { + // send a CC since CMTS has exhausted all + // protocol selection attempts + throw new COPSException("CMTS exhausted all protocol selection attempts"); + } + } + // send CAT response + Properties prop = new Properties(); + logger.debug("send CAT to the CMTS "); + COPSMsg catMsg = MessageFactory.getInstance().create(COPSHeader.COPS_OP_CAT, prop); + client.sendRequest(catMsg); + // wait for REQ msg + COPSMsg reqMsg = client.readMessage(); + // Client-Close + if (reqMsg.getHeader().isAClientClose()) { + COPSError error = ((COPSClientCloseMsg) opnMessage).getError(); + logger.debug("CMTS requetsed Client-Close"); + throw new PCMMException(new PCMMError(error.getErrCode(), error.getErrSubCode())); + } else // Request + if (reqMsg.getHeader().isARequest()) { + logger.debug("Received REQ message form CMTS"); + // end connection attempts + COPSReqMsg req = (COPSReqMsg) reqMsg; + // set the client handle to be used later by the + // gate-set + client.setClientHandle(req.getClientHandle().getId().str()); + COPSPdpDataProcess processor = null; + COPSPdpConnection copsPdpConnection = new COPSPdpConnection(opn.getPepId(), ((AbstractPCMMClient) client).getSocket(), processor); + copsPdpConnection.setKaTimer(((COPSClientAcceptMsg) catMsg).getKATimer().getTimerVal()); + pool.schedule(pool.adapt(copsPdpConnection)); + endNegotiation = true; + } else + throw new COPSException("Can't understand request"); + } else { + throw new COPSException("Can't understand request"); + } + } + } + // else raise exception. + } catch (Exception e) { + logger.error(e.getMessage()); + // no need to keep connection. + client.disconnect(); + return null; + } + return client; + } + + @Override + protected IPCMMClientHandler getPCMMClientHandler(Socket socket) { + // TODO Auto-generated method stub + return null; + } + + /** + * + * @see {@link IPSCMTSClient} + */ + /* public */static class PSCMTSClient extends AbstractPCMMClient implements + IPSCMTSClient { + /** + * Transaction id is + */ + private short transactionID; + private short classifierID; + private int gateID; + + public PSCMTSClient() { + super(); + logger.info("Client " + getClass() + hashCode() + " crated and started"); + } + + public PSCMTSClient(Socket socket) { + setSocket(socket); + } + + public boolean gateSet() { + logger.debug("Sending Gate-Set message"); + if (!isConnected()) + throw new IllegalArgumentException("Not connected"); + // XXX check if other values should be provided + // + ITrafficProfile trafficProfile = buildTrafficProfile(); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + ITransactionID trID = new TransactionID(); + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateSet); + transactionID = (short) (transactionID == 0 ? (short) (Math.random() * hashCode()) : transactionID); + trID.setTransactionIdentifier(transactionID); + // AMID + IAMID amid = getAMID(); + // GATE SPEC + IGateSpec gateSpec = getGateSpec(); + ISubscriberID subscriberID = new SubscriberID(); + // Classifier if MM version <4, Extended Classifier else + IClassifier eclassifier = getClassifier(subscriberID); + + IPCMMGate gate = new PCMMGateReq(); + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateSpec(gateSpec); + gate.setTrafficProfile(trafficProfile); + gate.setClassifier(eclassifier); + byte[] data = gate.getData(); + + // configure message properties + Properties prop = new Properties(); + prop.put(MessageProperties.CLIENT_HANDLE, getClientHandle()); + prop.put(MessageProperties.DECISION_CMD_CODE, COPSDecision.DEC_INSTALL); + prop.put(MessageProperties.DECISION_FLAG, (short) COPSDecision.DEC_NULL); + prop.put(MessageProperties.GATE_CONTROL, new COPSData(data, 0, data.length)); + COPSMsg decisionMsg = MessageFactory.getInstance().create(COPSHeader.COPS_OP_DEC, prop); + // ** Send the GateSet Decision + // ** + sendRequest(decisionMsg); + // TODO check on this ? + // waits for the gate-set-ack or error + COPSMsg responseMsg = readMessage(); + if (responseMsg.getHeader().isAReport()) { + logger.info("processing received report from CMTS"); + COPSReportMsg reportMsg = (COPSReportMsg) responseMsg; + if (reportMsg.getClientSI().size() == 0) { + logger.debug("CMTS responded with an empty SI"); + return false; + } + COPSClientSI clientSI = (COPSClientSI) reportMsg.getClientSI().elementAt(0); + IPCMMGate responseGate = new PCMMGateReq(clientSI.getData().getData()); + IPCMMError error = ((PCMMGateReq) responseGate).getError(); + if (error != null) { + logger.error(error.toString()); + return false; + } + logger.info("the CMTS has sent TransactionID :"+responseGate.getTransactionID()); + if (responseGate.getTransactionID() != null && responseGate.getTransactionID().getGateCommandType() == ITransactionID.GateSetAck) { + logger.info("the CMTS has sent a Gate-Set-Ack response"); + // here CMTS responded that he acknowledged the Gate-Set + // TODO do further check of Gate-Set-Ack GateID etc... + gateID = responseGate.getGateID().getGateID(); + return true; + } else { + return false; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.rcd.IPCMMPolicyServer#gateDelete() + */ + @Override + public boolean gateDelete() { + if (!isConnected()) { + logger.error("Not connected"); + return false; + } + ITransactionID trID = new TransactionID(); + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateDelete); + trID.setTransactionIdentifier(transactionID); + // AMID + IAMID amid = getAMID(); + // GATE SPEC + ISubscriberID subscriberID = new SubscriberID(); + try { + subscriberID.setSourceIPAddress(InetAddress.getLocalHost()); + } catch (UnknownHostException e1) { + logger.error(e1.getMessage()); + } + + IGateID gateIdObj = new GateID(); + gateIdObj.setGateID(gateID); + + IPCMMGate gate = new PCMMGateReq(); + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateID(gateIdObj); + + // configure message properties + Properties prop = new Properties(); + prop.put(MessageProperties.CLIENT_HANDLE, getClientHandle()); + prop.put(MessageProperties.DECISION_CMD_CODE, COPSDecision.DEC_INSTALL); + prop.put(MessageProperties.DECISION_FLAG, (short) COPSDecision.DEC_NULL); + byte[] data = gate.getData(); + prop.put(MessageProperties.GATE_CONTROL, new COPSData(data, 0, data.length)); + COPSMsg decisionMsg = MessageFactory.getInstance().create(COPSHeader.COPS_OP_DEC, prop); + // ** Send the GateSet Decision + // ** + try { + decisionMsg.writeData(getSocket()); + } catch (IOException e) { + logger.error("Failed to send the decision, reason: " + e.getMessage()); + return false; + } + // waits for the gate-delete-ack or error + COPSMsg responseMsg = readMessage(); + if (responseMsg.getHeader().isAReport()) { + logger.info("processing received report from CMTS"); + COPSReportMsg reportMsg = (COPSReportMsg) responseMsg; + if (reportMsg.getClientSI().size() == 0) { + return false; + } + COPSClientSI clientSI = (COPSClientSI) reportMsg.getClientSI().elementAt(0); + IPCMMGate responseGate = new PCMMGateReq(clientSI.getData().getData()); + IPCMMError error = ((PCMMGateReq) responseGate).getError(); + if (error != null) { + logger.error(error.toString()); + return false; + } + // here CMTS responded that he acknowledged the Gate-delete + // message + ITransactionID responseTransactionID = responseGate.getTransactionID(); + if (responseTransactionID != null && responseTransactionID.getGateCommandType() == ITransactionID.GateDeleteAck) { + // TODO check : Is this test needed ?? + if (responseGate.getGateID().getGateID() == gateID && responseTransactionID.getTransactionIdentifier() == transactionID) { + logger.info("the CMTS has sent a Gate-Delete-Ack response"); + return true; + } + } + + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.rcd.IPCMMPolicyServer#gateInfo() + */ + @Override + public boolean gateInfo() { + if (!isConnected()) { + logger.error("Not connected"); + return false; + } + ITransactionID trID = new TransactionID(); + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.GateInfo); + trID.setTransactionIdentifier(transactionID); + // AMID + IAMID amid = getAMID(); + // GATE SPEC + ISubscriberID subscriberID = new SubscriberID(); + try { + subscriberID.setSourceIPAddress(InetAddress.getLocalHost()); + } catch (UnknownHostException e1) { + logger.error(e1.getMessage()); + } + IGateID gateIdObj = new GateID(); + gateIdObj.setGateID(gateID); + + IPCMMGate gate = new PCMMGateReq(); + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateID(gateIdObj); + + // configure message properties + Properties prop = new Properties(); + prop.put(MessageProperties.CLIENT_HANDLE, getClientHandle()); + prop.put(MessageProperties.DECISION_CMD_CODE, COPSDecision.DEC_INSTALL); + prop.put(MessageProperties.DECISION_FLAG, (short) COPSDecision.DEC_NULL); + byte[] data = gate.getData(); + prop.put(MessageProperties.GATE_CONTROL, new COPSData(data, 0, data.length)); + COPSMsg decisionMsg = MessageFactory.getInstance().create(COPSHeader.COPS_OP_DEC, prop); + // ** Send the GateSet Decision + // ** + try { + decisionMsg.writeData(getSocket()); + } catch (IOException e) { + logger.error("Failed to send the decision, reason: " + e.getMessage()); + return false; + } + // waits for the gate-Info-ack or error + COPSMsg responseMsg = readMessage(); + if (responseMsg.getHeader().isAReport()) { + logger.info("processing received report from CMTS"); + COPSReportMsg reportMsg = (COPSReportMsg) responseMsg; + if (reportMsg.getClientSI().size() == 0) { + return false; + } + COPSClientSI clientSI = (COPSClientSI) reportMsg.getClientSI().elementAt(0); + IPCMMGate responseGate = new PCMMGateReq(clientSI.getData().getData()); + IPCMMError error = ((PCMMGateReq) responseGate).getError(); + ITransactionID responseTransactionID = responseGate.getTransactionID(); + if (error != null) { + logger.debug(responseTransactionID != null ? responseTransactionID.toString() : "returned Transaction ID is null"); + logger.error(error.toString()); + return false; + } + // here CMTS responded that he acknowledged the Gate-Info + // message + /* + * = + * [] + * ] [] [] + * [] [] [] + * [] [] + */ + if (responseTransactionID != null && responseTransactionID.getGateCommandType() == ITransactionID.GateInfoAck) { + // TODO need to implement missing data wrapper + logger.info("TransactionID : " + responseTransactionID.toString()); + logger.info("AMID :" + String.valueOf(responseGate.getAMID())); + logger.info("SubscriberID :" + String.valueOf(responseGate.getSubscriberID())); + logger.info("Traffic Profile :" + String.valueOf(responseGate.getTrafficProfile())); + logger.info("Gate Time Info :"); + logger.info("Gate Usage Info :"); + logger.info("GateState :"); + return true; + } + + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.pcmm.rcd.IPCMMPolicyServer#synchronize() + */ + @Override + public boolean gateSynchronize() { + if (!isConnected()) { + logger.error("Not connected"); + return false; + } + ITransactionID trID = new TransactionID(); + // set transaction ID to gate set + trID.setGateCommandType(ITransactionID.SynchRequest); + trID.setTransactionIdentifier(transactionID); + // AMID + IAMID amid = getAMID(); + // GATE SPEC + ISubscriberID subscriberID = new SubscriberID(); + try { + subscriberID.setSourceIPAddress(InetAddress.getLocalHost()); + } catch (UnknownHostException e1) { + logger.error(e1.getMessage()); + } + IGateID gateIdObj = new GateID(); + gateIdObj.setGateID(gateID); + + IPCMMGate gate = new PCMMGateReq(); + gate.setTransactionID(trID); + gate.setAMID(amid); + gate.setSubscriberID(subscriberID); + gate.setGateID(gateIdObj); + + // configure message properties + Properties prop = new Properties(); + prop.put(MessageProperties.CLIENT_HANDLE, getClientHandle()); + prop.put(MessageProperties.DECISION_CMD_CODE, COPSDecision.DEC_INSTALL); + prop.put(MessageProperties.DECISION_FLAG, (short) COPSDecision.DEC_NULL); + byte[] data = gate.getData(); + prop.put(MessageProperties.GATE_CONTROL, new COPSData(data, 0, data.length)); + COPSMsg decisionMsg = MessageFactory.getInstance().create(COPSHeader.COPS_OP_DEC, prop); + // ** Send the GateSet Decision + // ** + try { + decisionMsg.writeData(getSocket()); + } catch (IOException e) { + logger.error("Failed to send the decision, reason: " + e.getMessage()); + return false; + } + // waits for the gate-Info-ack or error + COPSMsg responseMsg = readMessage(); + if (responseMsg.getHeader().isAReport()) { + logger.info("processing received report from CMTS"); + COPSReportMsg reportMsg = (COPSReportMsg) responseMsg; + if (reportMsg.getClientSI().size() == 0) { + return false; + } + COPSClientSI clientSI = (COPSClientSI) reportMsg.getClientSI().elementAt(0); + IPCMMGate responseGate = new PCMMGateReq(clientSI.getData().getData()); + IPCMMError error = ((PCMMGateReq) responseGate).getError(); + ITransactionID responseTransactionID = responseGate.getTransactionID(); + if (error != null) { + logger.debug(responseTransactionID != null ? responseTransactionID.toString() : "returned Transaction ID is null"); + logger.error(error.toString()); + return false; + } + // here CMTS responded that he acknowledged the Gate-Info + // message + /* + * = + * [] + * ] [] [] + * [] [] [] + * [] [] + */ + if (responseTransactionID != null && responseTransactionID.getGateCommandType() == ITransactionID.SynchReport) { + // TODO need to implement missing data wrapper + logger.info("TransactionID : " + responseTransactionID.toString()); + logger.info("AMID :" + String.valueOf(responseGate.getAMID())); + logger.info("SubscriberID :" + String.valueOf(responseGate.getSubscriberID())); + logger.info("Traffic Profile :" + String.valueOf(responseGate.getTrafficProfile())); + logger.info("Gate Time Info :"); + logger.info("Gate Usage Info :"); + logger.info("GateState :"); + return true; + } + + } + return false; + } + + private IAMID getAMID() { + IAMID amid = new AMID(); + amid.setApplicationType((short) 1); + amid.setApplicationMgrTag((short) 1); + return amid; + } + + private IClassifier getClassifier(ISubscriberID subscriberID) { + IClassifier classifier = null; + // if the version major is less than 4 we need to use Classifier + if (getVersionInfo().getMajorVersionNB() >= 4) { + classifier = new ExtendedClassifier(); + // eclassifier.setProtocol(IClassifier.Protocol.NONE); + classifier.setProtocol(IClassifier.Protocol.TCP); + try { + InetAddress subIP = InetAddress.getByName(PCMMGlobalConfig.SubscriberID); + InetAddress srcIP = InetAddress.getByName(PCMMGlobalConfig.srcIP); + InetAddress dstIP = InetAddress.getByName(PCMMGlobalConfig.dstIP); + InetAddress mask = InetAddress.getByName(PCMMProperties.get(PCMMConstants.DEFAULT_MASK, String.class)); + subscriberID.setSourceIPAddress(subIP); + classifier.setSourceIPAddress(srcIP); + classifier.setDestinationIPAddress(dstIP); + ((IExtendedClassifier) classifier).setIPDestinationMask(mask); + ((IExtendedClassifier) classifier).setIPSourceMask(mask); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + ((IExtendedClassifier) classifier).setSourcePortStart(PCMMGlobalConfig.srcPort); + ((IExtendedClassifier) classifier).setSourcePortEnd(PCMMGlobalConfig.srcPort); + ((IExtendedClassifier) classifier).setDestinationPortStart(PCMMGlobalConfig.dstPort); + ((IExtendedClassifier) classifier).setDestinationPortEnd(PCMMGlobalConfig.dstPort); + ((IExtendedClassifier) classifier).setActivationState((byte) 0x01); + /* + * check if we have a stored value of classifierID else we just + * create one eclassifier.setClassifierID((short) 0x01); + */ + ((IExtendedClassifier) classifier).setClassifierID((short) (classifierID == 0 ? Math.random() * hashCode() : classifierID)); + // XXX - testie + // eclassifier.setClassifierID((short) 1); + ((IExtendedClassifier) classifier).setAction((byte) 0x00); + // XXX - temp default until Gate Modify is hacked in + // eclassifier.setPriority(PCMMGlobalConfig.EClassifierPriority); + classifier.setPriority((byte) 65); + + } else { + classifier = new Classifier(); + classifier.setProtocol(IClassifier.Protocol.TCP); + try { + InetAddress subIP = InetAddress.getByName(PCMMGlobalConfig.SubscriberID); + InetAddress srcIP = InetAddress.getByName(PCMMGlobalConfig.srcIP); + InetAddress dstIP = InetAddress.getByName(PCMMGlobalConfig.dstIP); + subscriberID.setSourceIPAddress(subIP); + classifier.setSourceIPAddress(srcIP); + classifier.setDestinationIPAddress(dstIP); + } catch (UnknownHostException unae) { + System.out.println("Error getByName" + unae.getMessage()); + } + classifier.setSourcePort(PCMMGlobalConfig.srcPort); + classifier.setDestinationPort(PCMMGlobalConfig.dstPort); + } + return classifier; + } + + /** + * + * @return GateSpec object + */ + private IGateSpec getGateSpec() { + IGateSpec gateSpec = new GateSpec(); + gateSpec.setDirection(Direction.UPSTREAM); + gateSpec.setDSCP_TOSOverwrite(DSCPTOS.OVERRIDE); + gateSpec.setTimerT1(PCMMGlobalConfig.GateT1); + gateSpec.setTimerT2(PCMMGlobalConfig.GateT2); + gateSpec.setTimerT3(PCMMGlobalConfig.GateT3); + gateSpec.setTimerT4(PCMMGlobalConfig.GateT4); + return gateSpec; + } + + /** + * creates a traffic profile with 3 envelops (Authorized, Reserved and + * Committed). + * + * @return Traffic profile + */ + private ITrafficProfile buildTrafficProfile() { + ITrafficProfile trafficProfile = new BestEffortService(BestEffortService.DEFAULT_ENVELOP); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop().setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop().setMaximumTrafficBurst(BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop().setRequestTransmissionPolicy(PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getAuthorizedEnvelop().setMaximumSustainedTrafficRate(PCMMGlobalConfig.DefaultLowBestEffortTrafficRate); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + ((BestEffortService) trafficProfile).getReservedEnvelop().setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getReservedEnvelop().setMaximumTrafficBurst(BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getReservedEnvelop().setRequestTransmissionPolicy(PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getReservedEnvelop().setMaximumSustainedTrafficRate(PCMMGlobalConfig.DefaultLowBestEffortTrafficRate); + // PCMMGlobalConfig.DefaultBestEffortTrafficRate); + + ((BestEffortService) trafficProfile).getCommittedEnvelop().setTrafficPriority(BestEffortService.DEFAULT_TRAFFIC_PRIORITY); + ((BestEffortService) trafficProfile).getCommittedEnvelop().setMaximumTrafficBurst(BestEffortService.DEFAULT_MAX_TRAFFIC_BURST); + ((BestEffortService) trafficProfile).getCommittedEnvelop().setRequestTransmissionPolicy(PCMMGlobalConfig.BETransmissionPolicy); + ((BestEffortService) trafficProfile).getCommittedEnvelop().setMaximumSustainedTrafficRate(PCMMGlobalConfig.DefaultLowBestEffortTrafficRate); + return trafficProfile; + } + + @Override + public short getClassifierId() { + return classifierID; + } + + @Override + public short getTransactionId() { + return transactionID; + } + + @Override + public int getGateId() { + return gateID; + } + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/rcd/package-info.java b/packetcable-driver/src/main/java/org/pcmm/rcd/package-info.java new file mode 100644 index 0000000..0d21830 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/rcd/package-info.java @@ -0,0 +1,11 @@ + +/** + *

+ * The Resource Control Domain (RCD) may be defined as a logical grouping of elements that provide connectivity and network resource level policy management along the packet forwarding paths to and from an end host. + * The RCD consists of CMTS and Policy Server entities whose responsibilities include management of resources along the packet forwarding paths. + *

+ * + * + */ +package org.pcmm.rcd; + diff --git a/packetcable-driver/src/main/java/org/pcmm/scd/IApplicationServer.java b/packetcable-driver/src/main/java/org/pcmm/scd/IApplicationServer.java new file mode 100644 index 0000000..a0862b3 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/scd/IApplicationServer.java @@ -0,0 +1,47 @@ +/** + @header@ + */ + +package org.pcmm.scd; + +/** + *

+ * The Application Server is a network entity that interfaces with the + * Application Manager that requests PacketCable Multimedia services on behalf + * of clients. The AS may reside on the MSO's network or it may reside outside + * of this domain and interact with the MSO network via a particular trust + * relationship. Similarly, the AS may be under direct control of the operator + * or it may be controlled by a third-party. Any given AS may communicate with + * one or more Application Managers. + *

+ *

+ * The AS will communicate with a client via a signaling protocol that is + * outside the scope of this specification. Using this unspecified protocol, the + * Domain policies. For client requests that pass these checks, the AS + * determines the particular QoS parameters necessary to deliver the service to + * the client, based upon its knowledge of the requested service. It then sends + * a request for these resources to the appropriate Application Manager, which + * may deny the request based upon additional Service Control Domain policies or + * may pass the request on to the Policy Server. + *

+ * + * + */ +public interface IApplicationServer { + + /** + * sets the Application Server's id + * + * @param id + * : the id of the AS + */ + void setASId(String id); + + /** + * gets the AS id + * + * @return AS id + */ + String getASId(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/scd/impl/package-info.java b/packetcable-driver/src/main/java/org/pcmm/scd/impl/package-info.java new file mode 100644 index 0000000..41213d0 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/scd/impl/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +/** + * + */ +package org.pcmm.scd.impl; diff --git a/packetcable-driver/src/main/java/org/pcmm/scd/package-info.java b/packetcable-driver/src/main/java/org/pcmm/scd/package-info.java new file mode 100644 index 0000000..b6c8651 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/scd/package-info.java @@ -0,0 +1,10 @@ +/** + *

+ * The Service Control Domain (SCD) is defined as a logical grouping of elements that offer applications and content to service subscribers. + * The Application Manager resides in the SCD. Note that there may be one or more SCDs related to a single RCD. Conversely, each RCD may interact with one or more SCDs. + *

+ * + * + */ +package org.pcmm.scd; + diff --git a/packetcable-driver/src/main/java/org/pcmm/state/IPCMMRecordKeepingServer.java b/packetcable-driver/src/main/java/org/pcmm/state/IPCMMRecordKeepingServer.java new file mode 100644 index 0000000..b4d4f1f --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/state/IPCMMRecordKeepingServer.java @@ -0,0 +1,11 @@ +/** + @header@ + */ +package org.pcmm.state; + +/** + * + */ +public interface IPCMMRecordKeepingServer { + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/state/IState.java b/packetcable-driver/src/main/java/org/pcmm/state/IState.java new file mode 100644 index 0000000..5f3cb6e --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/state/IState.java @@ -0,0 +1,19 @@ +/** + @header@ + */ + + +package org.pcmm.state; + +/** + *

+ * Object serving as a state holder, each stateful server should keep record of + * clients' state + *

+ * + * + * + */ +public interface IState { + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/state/IStateful.java b/packetcable-driver/src/main/java/org/pcmm/state/IStateful.java new file mode 100644 index 0000000..e0a64f7 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/state/IStateful.java @@ -0,0 +1,30 @@ +/** + @header@ + */ + + +package org.pcmm.state; + +/** + *

+ * Each stateful server should implement this interface, to be able to save and + * retrieve clients' state + *

+ * + * + * + */ +public interface IStateful { + + /** + * records the collected client state + */ + void recordState(); + + /** + * + * @return recorded state. + */ + IState getRecoredState(); + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/state/package-info.java b/packetcable-driver/src/main/java/org/pcmm/state/package-info.java new file mode 100644 index 0000000..76b19c0 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/state/package-info.java @@ -0,0 +1,4 @@ +/** + */ +package org.pcmm.state; + diff --git a/packetcable-driver/src/main/java/org/pcmm/utils/PCMMException.java b/packetcable-driver/src/main/java/org/pcmm/utils/PCMMException.java new file mode 100644 index 0000000..01e23e4 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/utils/PCMMException.java @@ -0,0 +1,23 @@ +/** + @header@ + */ + +package org.pcmm.utils; + +import org.pcmm.gates.IPCMMError; + +/** + * Defines the Exception that could be thrown by the API. + * + */ +public class PCMMException extends Exception { + + public PCMMException(IPCMMError error) { + this(error.getDescription(), error.getErrorCode()); + } + + public PCMMException(String message, int code) { + super("error code [" + code + "]" + message); + } + +} diff --git a/packetcable-driver/src/main/java/org/pcmm/utils/PCMMUtils.java b/packetcable-driver/src/main/java/org/pcmm/utils/PCMMUtils.java new file mode 100644 index 0000000..4762370 --- /dev/null +++ b/packetcable-driver/src/main/java/org/pcmm/utils/PCMMUtils.java @@ -0,0 +1,67 @@ +/** + @header@ + */ +package org.pcmm.utils; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class PCMMUtils { + + public static void WriteBinaryDump(String rootFileName, byte[] buffer) { + // Make this Unique + String fileName = "/tmp/" + rootFileName + "-" + java.util.UUID.randomUUID() + ".bin"; + try { + + System.out.println("Open fileName " + fileName); + FileOutputStream outputStream = new FileOutputStream(fileName); + + // write() writes as many bytes from the buffer + // as the length of the buffer. You can also + // use + // write(buffer, offset, length) + // if you want to write a specific number of + // bytes, or only part of the buffer. + outputStream.write(buffer); + + // Always close files. + outputStream.close(); + + System.out.println("Wrote " + buffer.length + " bytes"); + } catch (IOException ex) { + System.out.println("Error writing file '" + fileName + "'"); + // Or we could just do this: + // ex.printStackTrace(); + } + } + + public static byte[] ReadBinaryDump(String fileName) { + // The name of the file to open. + // String fileName = "COPSReportMessage.txt"; + try { + FileInputStream inputStream = new FileInputStream(fileName); + // Use this for reading the data. + byte[] buffer = new byte[inputStream.available()]; + // read fills buffer with data and returns + // the number of bytes read (which of course + // may be less than the buffer size, but + // it will never be more). + int total = inputStream.read(buffer); + + // Always close files. + inputStream.close(); + + System.out.println("Read " + total + " bytes"); + return buffer; + } catch (FileNotFoundException ex) { + System.out.println("Unable to open file '" + fileName + "'"); + } catch (IOException ex) { + System.out.println("Error reading file '" + fileName + "'"); + // Or we could just do this: + // ex.printStackTrace(); + } + return null; + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/common/COPSDebug.java b/packetcable-driver/src/main/java/org/umu/cops/common/COPSDebug.java new file mode 100644 index 0000000..400eeb0 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/common/COPSDebug.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ +package org.umu.cops.common; + +import java.io.PrintStream; + +/** + * Class to print debug and error messages. + * + * @version COPSDebug.java, v 3.00 2004 + * + */ +public class COPSDebug { + + static public final String ERROR_NOEXPECTEDMSG = "Message not expected"; + static public final String ERROR_EXCEPTION = "Exception not expected"; + static public final String ERROR_SOCKET = "Error socket"; + static public final String ERROR_NOSUPPORTED = "Object not supported"; + + static public PrintStream _err = System.err; + + /** Prints an error message. + * + * @param cname Name of class that generated the error + * @param str Error message + * + */ + public static void err (String cname, String str) { + if (_err != null) + _err.println(cname + ":" + str); + } + + /** Prints an error message. + * + * @param cname Name of class that generated the error + * @param str Error message + * @param e Exception + * + */ + public static void err (String cname, String str, Exception e) { + if (_err != null) { + _err.println(cname + ":" + str); + _err.println(" -Reason: " + e.getMessage()); + } + } + + /** Prints an error message. + * + * @param cname Name of class that generated the error + * @param str Error message + * @param extra Information + * @param e Exception + * + */ + public static void err (String cname, String str, String extra, Exception e) { + if (_err != null) { + _err.println(cname + ":" + str); + _err.println(" -Info: " + extra); + _err.println(" -Reason: " + e.getMessage()); + } + } + + /** Prints an error message. + * + * @param cname Name of class that generated the error + * @param str Error message + * @param extra Information + * + */ + public static void err (String cname, String str, String extra) { + if (_err != null) { + _err.println(cname + ":" + str); + _err.println(" -Info: " + extra); + } + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/common/COPS_def.java b/packetcable-driver/src/main/java/org/umu/cops/common/COPS_def.java new file mode 100644 index 0000000..654bd9a --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/common/COPS_def.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ +package org.umu.cops.common; + +/** + * Class containing keywords supported by the client types. + * + * @version COPS_def.java, v 2.00 2004 + * + */ +public class COPS_def { + + /** COPS Client Type for RSVP + */ + public final static short C_RSVP = 1; + + /** COPS Client Type for SIP + */ + public final static short C_SIP = 100; + + /** COPS Client Type for IPSec + */ + public final static short C_IPSEC = (short) 0x8001; + + /** Maximum COPS Client Type + */ + public final static short C_MAX = (short) 0xFFFF; + + /** Get a representative string for an COPS Client Type. + * + * @param cType COPS Client Type + * @return A representative String + * + */ + public String strClientType(short cType) { + switch (cType) { + case C_RSVP: + return ("C_RSVP"); + case C_SIP: + return ("C_SIP"); + case C_IPSEC: + return ("C_IPSEC"); + default: + return "Unknown"; + } + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpException.java b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpException.java new file mode 100644 index 0000000..9375888 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpException.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.ospdp; + +/** + * COPS PEP Exception + * + * @version COPSPepException.java, v 2.00 2004 + * + */ +public class COPSPdpException extends Exception { + + private int rc; + final static int GENERAL_ERROR = 0x00000001; + + /** + * Creates a COPSPdpException with the given message. + * @param msg Exception message + */ + public COPSPdpException(String msg) { + super(msg); + rc=0; + } + + /** + * Creates a COPSPdpException with the given message and return code. + * @param msg Exception message + * @param retCode Return code + */ + public COPSPdpException(String msg, int retCode) { + super(msg); + rc = retCode; + } + + /** + * Gets the return code of the exception + * @return Exception's return code + */ + public int returnCode() { + return rc; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSAgent.java b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSAgent.java new file mode 100644 index 0000000..354bf76 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSAgent.java @@ -0,0 +1,317 @@ +package org.umu.cops.ospdp; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSTransceiver; + +/** + * Core PDP agent for outsourcing. + */ +public class COPSPdpOSAgent extends Thread { + /** Well-known port for COPS */ + public static final int WELL_KNOWN_PDP_PORT = 3288; + /** Default keep-alive timer value (secs) */ + public static final short KA_TIMER_VALUE = 30; + /** Default accounting timer value (secs) */ + public static final short ACCT_TIMER_VALUE = 0; + + /** + PDP host IP + */ + private ServerSocket _serverSocket; + + /** + PDP host port + */ + private int _serverPort; + + /** + Client-type of connecting PEP + */ + private short _clientType; + + /** + Accounting timer (secs) + */ + private short _acctTimer; + + /** + Keep-alive timer (secs) + */ + private short _kaTimer; + + /** + Maps a PEP-ID to a connection + */ + private Hashtable _connectionMap; + // map < String(PEPID), COPSPdpOSConnection > ConnectionMap; + + /** + * Policy data processing object + */ + private COPSPdpOSDataProcess _process; + + /** + * Creates a PDP Agent + * + * @param clientType COPS Client-type + * @param process Object to perform policy data processing + */ + public COPSPdpOSAgent(short clientType, COPSPdpOSDataProcess process) { + _serverPort = WELL_KNOWN_PDP_PORT; + _kaTimer = KA_TIMER_VALUE; + _acctTimer = ACCT_TIMER_VALUE; + + _clientType = clientType; + _connectionMap = new Hashtable(40); + _process = process; + } + + /** + * Creates a PDP Agent + * + * @param port Port to listen to + * @param clientType COPS Client-type + * @param process Object to perform policy data processing + */ + public COPSPdpOSAgent(int port, short clientType, COPSPdpOSDataProcess process) { + _serverPort = port; + + _kaTimer = KA_TIMER_VALUE; + _acctTimer = ACCT_TIMER_VALUE; + + _clientType = clientType; + _connectionMap = new Hashtable(40); + _process = process; + } + + /** + * Sets the keep-alive timer value + * @param kaTimer Keep alive timer value (secs) + */ + public void setKaTimer (short kaTimer) { + _kaTimer = kaTimer; + } + + /** + * Sets the accounting timer value + * @param acctTimer Accounting timer value (secs) + */ + public void setAcctTimer (short acctTimer) { + _acctTimer = acctTimer; + } + + /** + * Gets the value of the keep-alive timer + * @return Keep-alive timer value (secs) + */ + public short getKaTimer () { + return _kaTimer; + } + + /** + * Gets the accounting timer value + * @return Accounting timer value (secs) + */ + public short getAcctTimer () { + return _acctTimer; + } + + /** + * Gets the PEPs connected to this PDP + * @return An Enumeration of all connected PEPs + */ + public Enumeration getConnectedPEPIds() { + return _connectionMap.keys(); + } + + /** + * Gets the connection map + * @return A Hashtable holding the connection map + */ + public Hashtable getConnectionMap() { + return _connectionMap; + } + + /** + * Gets the client-type + * @return The client-type + */ + public short getClientType() { + return _clientType; + } + + /** + * Disconnects a PEP + * @param pepID PEP-ID of the PEP to be disconnected + * @param error COPS Error to be reported as a reason + * @throws COPSException + * @throws IOException + */ + public void disconnect (String pepID, COPSError error) throws COPSException, IOException { + COPSPdpOSConnection pdpConn = (COPSPdpOSConnection) _connectionMap.get(pepID); + + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, _clientType); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + if (error != null) + closeMsg.add(error); + + closeMsg.writeData(pdpConn.getSocket()); + pdpConn.close(); + pdpConn = null; + } + + /** + * Requests a COPS sync for a PEP + * @param pepID PEP-ID of the PEP to be synced + * @throws COPSException + * @throws COPSPdpException + */ + public void sync(String pepID) throws COPSException, COPSPdpException { + COPSPdpOSConnection pdpConn = (COPSPdpOSConnection) _connectionMap.get(pepID); + pdpConn.syncAllRequestState(); + } + + /** + * Removes a PEP from the connection map + * @param pepID PEP-ID of the PEP to be removed + */ + public void delete (String pepID) { + _connectionMap.remove(pepID); + } + + /** + * Runs the PDP process + */ + public void run() { + try { + _serverSocket = new ServerSocket (_serverPort); + + //Loop through for Incoming messages + + // server infinite loop + while (true) { + // Wait for an incoming connection from a PEP + Socket socket = _serverSocket.accept(); + + // COPSDebug.out(getClass().getName(),"New connection accepted " + + // socket.getInetAddress() + + // ":" + socket.getPort()); + + // We're waiting for an OPN message + try { + COPSMsg msg = COPSTransceiver.receiveMsg(socket); + if (msg.getHeader().isAClientOpen()) { + handleClientOpenMsg(socket, msg); + } else { + // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + try { + socket.close(); + } catch (Exception ex) {}; + } + } catch (Exception e) { // COPSException, IOException + // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_EXCEPTION, + // "(" + socket.getInetAddress() + ":" + socket.getPort() + ")", e); + try { + socket.close(); + } catch (Exception ex) {}; + } + } + } catch (IOException e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + return; + } + } + + /** + * Handles a COPS client-open message + * @param conn Socket to the PEP + * @param msg COPSMsg holding the client-open message + * @throws COPSException + * @throws IOException + */ + private void handleClientOpenMsg(Socket conn, COPSMsg msg) throws COPSException, IOException { + COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg; + COPSPepId pepId = cMsg.getPepId(); + + // Validate Client Type + if (msg.getHeader().getClientType() != _clientType) { + // Unsupported client type + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_UNSUPPORTED_CLIENT_TYPE, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) {} + + throw new COPSException("Unsupported client type"); + } + + // PEPId is mandatory + if (pepId == null) { + // Mandatory COPS object missing + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_MANDATORY_OBJECT_MISSING, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) {} + + throw new COPSException("Mandatory COPS object missing (PEPId)"); + } + + // Support + if ( (cMsg.getClientSI() != null) || + (cMsg.getPdpAddress() != null) || + (cMsg.getIntegrity() != null)) { + + // Unsupported objects + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_UNKNOWN_OBJECT, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) {} + + throw new COPSException("Unsupported objects (ClientSI, PdpAddress, Integrity)"); + } + + // Connection accepted + COPSHeader ahdr = new COPSHeader(COPSHeader.COPS_OP_CAT, msg.getHeader().getClientType()); + COPSKATimer katimer = new COPSKATimer(_kaTimer); + COPSAcctTimer acctTimer = new COPSAcctTimer(_acctTimer); + COPSClientAcceptMsg acceptMsg = new COPSClientAcceptMsg(); + acceptMsg.add(ahdr); + acceptMsg.add(katimer) ; + if (_acctTimer != 0) acceptMsg.add(acctTimer); + acceptMsg.writeData(conn); + + COPSPdpOSConnection pdpConn = new COPSPdpOSConnection(pepId, conn, _process); + pdpConn.setKaTimer(_kaTimer); + if (_acctTimer != 0) pdpConn.setAccTimer(_acctTimer); + new Thread(pdpConn).start(); + _connectionMap.put(pepId.getData().str(),pdpConn); + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSConnection.java b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSConnection.java new file mode 100644 index 0000000..39890b7 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSConnection.java @@ -0,0 +1,544 @@ +package org.umu.cops.ospdp; + +import java.io.IOException; +import java.net.Socket; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKAMsg; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; +import org.umu.cops.stack.COPSTransceiver; + +/** + * Class for managing an outsourcing connection at the PDP side. + */ +public class COPSPdpOSConnection implements Runnable { + /** + Socket connected to PEP + */ + private Socket _sock; + + /** + PEP identifier + */ + private COPSPepId _pepId; + + /** + Time of the latest keep-alive sent + */ + private Date _lastKa; + + /** + Opcode of the latest message sent + */ + private byte _lastmessage; + + /** + * Time of the latest keep-alive received + */ + protected Date _lastRecKa; + + /** + Maps a Client Handle to a Handler + */ + protected Hashtable _managerMap; + // map < String(COPSHandle), COPSPdpHandler> HandlerMap; + + /** + * PDP policy data processor class + */ + protected COPSPdpOSDataProcess _process; + + /** + Accounting timer value (secs) + */ + protected short _acctTimer; + + /** + Keep-alive timer value (secs) + */ + protected short _kaTimer; + + /** + COPS error returned by PEP + */ + protected COPSError _error; + + /** + * Creates a new PDP connection + * + * @param pepId PEP-ID of the connected PEP + * @param sock Socket connected to PEP + * @param process Object for processing policy data + */ + public COPSPdpOSConnection(COPSPepId pepId, Socket sock, COPSPdpOSDataProcess process) { + _sock = sock; + _pepId = pepId; + + _lastKa = new Date(); + _lastmessage = COPSHeader.COPS_OP_OPN; + _managerMap = new Hashtable(20); + + _kaTimer = 0; + _process = process; + } + + /** + * Gets the time of that latest keep-alive sent + * @return Time of that latest keep-alive sent + */ + public Date getLastKAlive() { + return _lastKa; + } + + /** + * Sets the keep-alive timer value + * @param kaTimer Keep-alive timer value (secs) + */ + public void setKaTimer(short kaTimer) { + _kaTimer = kaTimer; + } + + /** + * Gets the keep-alive timer value + * @return Keep-alive timer value (secs) + */ + public short getKaTimer() { + return _kaTimer; + } + + /** + * Sets the accounting timer value + * @param acctTimer Accounting timer value (secs) + */ + public void setAccTimer(short acctTimer) { + _acctTimer = acctTimer; + } + + /** + * Gets the accounting timer value + * @return Accounting timer value (secs) + */ + public short getAcctTimer() { + return _acctTimer; + } + + /** + * Gets the latest COPS message + * @return Code of the latest message sent + */ + public byte getLastMessage() { + return _lastmessage; + } + + /** + * Gets active handles + * @return An Enumeration holding all active handles + */ + public Enumeration getHandles() { + return _managerMap.keys(); + } + + /** + * Gets the handle map + * @return A Hashtable holding the handle map + */ + public Hashtable getReqStateMans() { + return _managerMap; + } + + /** + * Gets the PEP-ID + * @return The ID of the PEP, as a String + */ + public String getPepId() { + return _pepId.getData().str(); + } + + /** + * Checks whether the socket to the PEP is closed or not + * @return true if closed, false otherwise + */ + public boolean isClosed() { + return _sock.isClosed(); + } + + /** + * Closes the socket to the PEP + * @throws IOException + */ + protected void close() + throws IOException { + _sock.close(); + } + + /** + * Gets the socket to the PEP + * @return Socket connected to the PEP + */ + public Socket getSocket() { + return _sock; + } + + /** + * Main loop + */ + public void run () { + Date _lastSendKa = new Date(); + _lastRecKa = new Date(); + try { + while (!_sock.isClosed()) { + if (_sock.getInputStream().available() != 0) { + _lastmessage = processMessage(_sock); + _lastRecKa = new Date(); + } + + // Keep Alive + if (_kaTimer > 0) { + // Timeout at PDP + int _startTime = (int) (_lastRecKa.getTime()); + int cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > _kaTimer*1000) { + _sock.close(); + // Notify all Request State Managers + notifyNoKAAllReqStateMan(); + } + + // Send to PEP + _startTime = (int) (_lastSendKa.getTime()); + cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > ((_kaTimer*3/4)*1000)) { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA); + COPSKAMsg msg = new COPSKAMsg(); + + msg.add(hdr); + + COPSTransceiver.sendMsg(msg, _sock); + _lastSendKa = new Date(); + } + } + + try { + Thread.sleep(500); + } catch (Exception e) {}; + + } + } catch (Exception e) { + e.printStackTrace(); + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } + + // connection closed by server + // COPSDebug.out(getClass().getName(),"Connection closed by client"); + try { + _sock.close(); + } catch (IOException e) {}; + + // Notify all Request State Managers + try { + notifyCloseAllReqStateMan(); + } catch (COPSPdpException e) {}; + } + + /** + * Gets a COPS message from the socket and processes it + * @param conn Socket connected to the PEP + * @return Type of COPS message + */ + private byte processMessage(Socket conn) + throws COPSPdpException, COPSException, IOException { + COPSMsg msg = COPSTransceiver.receiveMsg(conn); + + if (msg.getHeader().isAClientClose()) { + handleClientCloseMsg(conn, msg); + return COPSHeader.COPS_OP_CC; + } else if (msg.getHeader().isAKeepAlive()) { + handleKeepAliveMsg(conn, msg); + return COPSHeader.COPS_OP_KA; + } else if (msg.getHeader().isARequest()) { + handleRequestMsg(conn, msg); + return COPSHeader.COPS_OP_REQ; + } else if (msg.getHeader().isAReport()) { + handleReportMsg(conn, msg); + return COPSHeader.COPS_OP_RPT; + } else if (msg.getHeader().isADeleteReq()) { + handleDeleteRequestMsg(conn, msg); + return COPSHeader.COPS_OP_DRQ; + } else if (msg.getHeader().isASyncComplete()) { + handleSyncComplete(conn, msg); + return COPSHeader.COPS_OP_SSC; + } else { + throw new COPSPdpException("Message not expected (" + msg.getHeader().getOpCode() + ")."); + } + } + + /** + * Handle Client Close Message, close the passed connection + * + * @param conn a Socket + * @param msg a COPSMsg + * + * + * ::= + * + * [] + * + * Not support [] + * + */ + private void handleClientCloseMsg(Socket conn, COPSMsg msg) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg; + _error = cMsg.getError(); + + // COPSDebug.out(getClass().getName(),"Got close request, closing connection " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]"); + + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + conn.close(); + } catch (Exception unae) { }; + } + + /** + * Gets the occurred COPS Error + * @return COPSError object + */ + protected COPSError getError() { + return _error; + } + + /** + * Handle Keep Alive Message + * + * ::= + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleKeepAliveMsg(Socket conn, COPSMsg msg) { + COPSKAMsg cMsg = (COPSKAMsg) msg; + + COPSKAMsg kaMsg = (COPSKAMsg) msg; + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + kaMsg.writeData(conn); + } catch (Exception unae) { }; + } + + /** + * Handle Delete Request Message + * + * ::= + * + * + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleDeleteRequestMsg(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSDeleteMsg cMsg = (COPSDeleteMsg) msg; + // COPSDebug.out(getClass().getName(),"Removing ClientHandle for " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Reason " + cMsg.getReason().getDescription() + "]"); + + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + // Delete clientHandler + if (_managerMap.remove(cMsg.getClientHandle().getId().str()) == null) { + // COPSDebug.out(getClass().getName(),"Missing for ClientHandle " + + // cMsg.getClientHandle().getId().getData()); + } + + COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processDeleteRequestState(cMsg); + } + + } + + /** + * Handle Request Message + * + * ::= + * + * + * *() + * [] + * ::= <*( )> + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleRequestMsg(Socket conn, COPSMsg msg) throws COPSPdpException { + COPSReqMsg reqMsg = (COPSReqMsg) msg; + COPSContext cntxt = reqMsg.getContext(); + COPSHeader header = reqMsg.getHeader(); + //short reqType = cntxt.getRequestType(); + short cType = header.getClientType(); + + // Support + if (reqMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + COPSPdpOSReqStateMan man; + man = (COPSPdpOSReqStateMan) _managerMap.get(reqMsg.getClientHandle().getId().str()); + if (man == null) { + man = new COPSPdpOSReqStateMan(cType, reqMsg.getClientHandle().getId().str()); + _managerMap.put(reqMsg.getClientHandle().getId().str(),man); + man.setDataProcess(_process); + man.initRequestState(_sock); + + // COPSDebug.out(getClass().getName(),"createHandler called, clientType=" + + // header.getClientType() + " msgType=" + + // cntxt.getMessageType() + ", connId=" + conn.toString()); + } + + man.processRequest(reqMsg); + } + + /** + * Handle Report Message + * + * ::= + * + * + * *() + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleReportMsg(Socket conn, COPSMsg msg) throws COPSPdpException { + COPSReportMsg repMsg = (COPSReportMsg) msg; + // COPSHandle handle = repMsg.getClientHandle(); + // COPSHeader header = repMsg.getHeader(); + + // Support + if (repMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(repMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processReport(repMsg); + } + } + + /** + * Method handleSyncComplete + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleSyncComplete(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg; + // COPSHandle handle = cMsg.getClientHandle(); + // COPSHeader header = cMsg.getHeader(); + + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processSyncComplete(cMsg); + } + } + + /** + * Requests a COPS sync from the PEP + * @throws COPSException + * @throws COPSPdpException + */ + protected void syncAllRequestState() + throws COPSException, COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle); + + man.syncRequestState(); + } + } + } + + private void notifyCloseAllReqStateMan() + throws COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle); + + man.processClosedConnection(_error); + } + } + } + + private void notifyNoKAAllReqStateMan() + throws COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle); + + man.processNoKAConnection(); + } + } + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSDataProcess.java b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSDataProcess.java new file mode 100644 index 0000000..4a5e438 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSDataProcess.java @@ -0,0 +1,78 @@ +package org.umu.cops.ospdp; + +import java.util.Vector; + +import org.umu.cops.stack.COPSError; + +/** + * Abstract class for implementing policy data processing classes for outsourcing PDPs. + */ +abstract public class COPSPdpOSDataProcess { + /** + * Gets the policies to be uninstalled + * @param man The associated request state manager + * @return A Vector holding the policies to be uninstalled + */ + abstract public Vector getRemovePolicy(COPSPdpOSReqStateMan man); + /** + * Gets the policies to be installed + * @param man The associated request state manager + * @return A Vector holding the policies to be uninstalled + */ + abstract public Vector getInstallPolicy(COPSPdpOSReqStateMan man); + /** + * Makes a decision from the supplied request data + * @param man The associated request state manager + * @param reqSIs Client specific data suppplied in the COPS request + */ + abstract public void setClientData(COPSPdpOSReqStateMan man, Vector reqSIs); + /** + * Builds a failure report + * @param man The associated request state manager + * @param reportSIs Report data + */ + abstract public void failReport (COPSPdpOSReqStateMan man, Vector reportSIs); + /** + * Builds a success report + * @param man The associated request state manager + * @param reportSIs Report data + */ + abstract public void successReport (COPSPdpOSReqStateMan man, Vector reportSIs); + /** + * Builds an accounting report + * @param man The associated request state manager + * @param reportSIs Report data + */ + abstract public void acctReport (COPSPdpOSReqStateMan man, Vector reportSIs); + /** + * Notifies that no accounting report has been received + * @param man The associated request state manager + */ + public abstract void notifyNoAcctReport (COPSPdpOSReqStateMan man); + + /** + * Notifies a keep-alive timeout + * @param man The associated request state manager + */ + public abstract void notifyNoKAliveReceived (COPSPdpOSReqStateMan man); + + /** + * Notifies that the connection has been closed + * @param man The associated request state manager + * @param error Reason + */ + public abstract void notifyClosedConnection (COPSPdpOSReqStateMan man, COPSError error); + + /** + * Notifies that a request state has been deleted + * @param man The associated request state manager + */ + public abstract void notifyDeleteRequestState (COPSPdpOSReqStateMan man); + + /** + * Notifies that a request state has been closed + * @param man The associated request state manager + */ + public abstract void closeRequestState(COPSPdpOSReqStateMan man); + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSMsgSender.java b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSMsgSender.java new file mode 100644 index 0000000..c341328 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSMsgSender.java @@ -0,0 +1,288 @@ +package org.umu.cops.ospdp; + +import java.io.IOException; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Vector; + +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * COPS message transceiver class for outsourcing connections at the PDP side. + */ +public class COPSPdpOSMsgSender { + /** + * Socket connected to PEP + */ + protected Socket _sock; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + * Creates a COPSPepMsgSender + * + * @param clientType COPS client-type + * @param clientHandle Client handle + * @param sock Socket to the PEP + */ + public COPSPdpOSMsgSender (short clientType, COPSHandle clientHandle, Socket sock) { + // COPS Handle + _handle = clientHandle; + _clientType = clientType; + + _sock = sock; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the client-type + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Sends a decision message which was requested by the PEP + * @param removeDecs Decisions to be removed + * @param installDecs Decisions to be installed + * @throws COPSPdpException + */ + public void sendSolicitedDecision(Vector removeDecs, Vector installDecs) throws COPSPdpException { + sendDecision(removeDecs, installDecs, true); + } + + /** + * Sends a decision message which was not requested by the PEP + * @param removeDecs Decisions to be removed + * @param installDecs Decisions to be installed + * @throws COPSPdpException + */ + public void sendUnsolicitedDecision(Vector removeDecs, Vector installDecs) throws COPSPdpException { + sendDecision(removeDecs, installDecs, false); + } + + /** + * Sends a decision message to the PEP + * @param removeDecs Decisions to be removed + * @param installDecs Decisions to be installed + * @param solicited true if the PEP requested this decision, false otherwise + * @throws COPSPdpException + */ + public void sendDecision(Vector removeDecs, Vector installDecs, boolean solicited) throws COPSPdpException { + // Common Header holding the same ClientType as the request + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_DEC, getClientType()); + + if (solicited) + hdr.setFlag(COPSHeader.COPS_FLAG_SOLICITED); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + handle.setId(getClientHandle().getId()); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + + // Remove Decisions + // + if (removeDecs.size() > 0) { + COPSDecision rdec1 = new COPSDecision(); + rdec1.setCmdCode(COPSDecision.DEC_REMOVE); + + decisionMsg.addDecision(rdec1, cntxt); + + Enumeration removeDecsEnum = removeDecs.elements(); + while (removeDecsEnum.hasMoreElements()) + decisionMsg.addDecision((COPSDecision) removeDecsEnum.nextElement(), cntxt); + } + + // Install Decisions + // + if (installDecs.size() > 0) { + COPSDecision idec1 = new COPSDecision(); + idec1.setCmdCode(COPSDecision.DEC_INSTALL); + + decisionMsg.addDecision(idec1, cntxt); + + Enumeration installDecsEnum = installDecs.elements(); + while (installDecsEnum.hasMoreElements()) + decisionMsg.addDecision((COPSDecision) installDecsEnum.nextElement(), cntxt); + /** + COPSIntegrity intr = new COPSIntegrity(); + intr.setKeyId(19); + intr.setSeqNum(9); + intr.setKeyDigest(new COPSData("KEY DIGEST")); + decisionMsg.add(intr); + /**/ + } + } catch (COPSException e) { + e.printStackTrace(); + throw new COPSPdpException("Error making Msg"); + } + + //** Send decision + //** + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the decision, reason: " + e.getMessage()); + } + } + + /**FIXME: unused? + * Sends a message asking that the request state be deleted + * @throws COPSPdpException + */ + public void sendDeleteRequestState() throws COPSPdpException { + /* ::= + * + * *() + * [] + * ::= + * + * ::= Remove Request-State + * + */ + + // Common Header with the same ClientType as the request (default UNSOLICITED) + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + // Decisions + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + // + COPSDecision dec = new COPSDecision(); + dec.setCmdCode(COPSDecision.DEC_REMOVE); + dec.setFlags(COPSDecision.F_REQSTATE); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(clienthandle); + decisionMsg.addDecision(dec, cntxt); + } catch (COPSException e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the open new request state, reason: " + e.getMessage()); + } + } + + /** + * Method sendOpenNewRequestState + * + * @throws COPSPdpException + * + */ + //FIXME: Unused? + public void sendOpenNewRequestState() throws COPSPdpException { + /* ::= + * + * *() + * [] + * ::= + * + * ::= Install Request-State + * + */ + + // Common Header with the same ClientType as the request (default UNSOLICITED) + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + // Decisions + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + // + COPSDecision dec = new COPSDecision(); + dec.setCmdCode(COPSDecision.DEC_INSTALL); + dec.setFlags(COPSDecision.F_REQSTATE); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(clienthandle); + decisionMsg.addDecision(dec, cntxt); + } catch (COPSException e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the open new request state, reason: " + e.getMessage()); + } + } + + /** + * Sends a message asking for a COPS sync operation + * @throws COPSPdpException + */ + public void sendSyncRequestState() + throws COPSPdpException { + /* ::= + * [] + * [] + */ + + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_SSQ, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + COPSSyncStateMsg msg = new COPSSyncStateMsg(); + try { + msg.add(hdr); + msg.add(clienthandle); + } catch (Exception e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the sync state request, reason: " + e.getMessage()); + } + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSReqStateMan.java b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSReqStateMan.java new file mode 100644 index 0000000..ffd379c --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospdp/COPSPdpOSReqStateMan.java @@ -0,0 +1,310 @@ +package org.umu.cops.ospdp; + +import java.net.Socket; +import java.util.Vector; + +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReportType; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * State manager class for outsourcing requests, at the PDP side. + */ +public class COPSPdpOSReqStateMan { + /** + * Request State created + */ + public final static short ST_CREATE = 1; + /** + * Request received + */ + public final static short ST_INIT = 2; + /** + * Decisions sent + */ + public final static short ST_DECS = 3; + /** + * Report received + */ + public final static short ST_REPORT = 4; + /** + * Request state finalized + */ + public final static short ST_FINAL = 5; + /** + * New request state solicited + */ + public final static short ST_NEW = 6; + /** + * Delete request state solicited + */ + public final static short ST_DEL = 7; + /** + * SYNC request sent + */ + public final static short ST_SYNC = 8; + /** + * SYNC completed + */ + public final static short ST_SYNCALL = 9; + /** + * Close connection received + */ + public final static short ST_CCONN = 10; + /** + * Keep-alive timeout + */ + public final static short ST_NOKA = 11; + /** + * Accounting timeout + */ + public final static short ST_ACCT = 12; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + * Object for performing policy data processing + */ + protected COPSPdpOSDataProcess _process; + + /** + * Current state of the request being managed + */ + protected short _status; + + /** COPS message transceiver used to send COPS messages */ + protected COPSPdpOSMsgSender _sender; + + /** + * Creates a request state manager + * @param clientType Client-type + * @param clientHandle Client handle + */ + public COPSPdpOSReqStateMan(short clientType, String clientHandle) { + // COPS Handle + _handle = new COPSHandle(); + COPSData id = new COPSData(clientHandle); + _handle.setId(id); + // client-type + _clientType = clientType; + + _status = ST_CREATE; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the client-type + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Gets the status of the request + * @return Request state value + */ + public short getStatus() { + return _status; + } + + /** + * Gets the policy data processing object + * @return Policy data processing object + */ + public COPSPdpOSDataProcess getDataProcess() { + return _process; + } + + /** + * Sets the policy data processing object + * @param process Policy data processing object + */ + public void setDataProcess(COPSPdpOSDataProcess process) { + _process = process; + } + + /** + * Called when COPS sync is completed + * @param repMsg COPS sync message + * @throws COPSPdpException + */ + protected void processSyncComplete(COPSSyncStateMsg repMsg) + throws COPSPdpException { + + _status = ST_SYNCALL; + + // maybe we should notifySyncComplete ... + } + + /** + * Initializes a new request state over a socket + * @param sock Socket to the PEP + * @throws COPSPdpException + */ + protected void initRequestState(Socket sock) + throws COPSPdpException { + // Inits an object for sending COPS messages to the PDP + _sender = new COPSPdpOSMsgSender(_clientType, _handle, sock); + + // Initial state + _status = ST_INIT; + } + + /** + * Processes a COPS request + * @param msg COPS request received from the PEP + * @throws COPSPdpException + */ + protected void processRequest(COPSReqMsg msg) throws COPSPdpException { + Vector clientSIs = msg.getClientSI(); + + //** Here we must retrieve a decision depending on the + //** supplied ClientSIs + /*Vector removeDecs = new Vector(); + Vector installDecs = new Vector();*/ + _process.setClientData(this, clientSIs); + + Vector removeDecs = _process.getRemovePolicy(this); + Vector installDecs = _process.getInstallPolicy(this); + + //** We create a SOLICITED decision + //** + _sender.sendSolicitedDecision(removeDecs, installDecs); + _status = ST_DECS; + } + + /** + * Processes a report + * @param msg Report message from the PEP + * @throws COPSPdpException + */ + protected void processReport(COPSReportMsg msg) throws COPSPdpException { + //** Analyze the report + //** + + /* + * ::= + * + * + * *() + * [] + * ::= <[] *()> + * ::= *() + * + * Important, is not parsed + */ + + // COPSHeader hdrmsg = msg.getHeader(); + // COPSHandle handlemsg = msg.getClientHandle(); + + // Report Type + COPSReportType rtypemsg = msg.getReport(); + + // Named ClientSI + Vector clientSIs = msg.getClientSI(); + + //** We should act here in accordance with + //** the received report + if (rtypemsg.isSuccess()) { + _status = ST_REPORT; + _process.successReport(this, clientSIs); + } else if (rtypemsg.isFailure()) { + _status = ST_REPORT; + _process.failReport(this, clientSIs); + } else if (rtypemsg.isAccounting()) { + _status = ST_ACCT; + _process.acctReport(this, clientSIs); + } + } + + /** + * Called when connection is closed + * @param error Reason + * @throws COPSPdpException + */ + protected void processClosedConnection(COPSError error) + throws COPSPdpException { + if (_process != null) + _process.notifyClosedConnection(this, error); + + _status = ST_CCONN; + } + + /** + * Called when no keep-alive is received + * @throws COPSPdpException + */ + protected void processNoKAConnection() + throws COPSPdpException { + if (_process != null) + _process.notifyNoKAliveReceived(this); + + _status = ST_NOKA; + } + + /** + * Deletes the request state + * @throws COPSPdpException + */ + protected void finalizeRequestState() + throws COPSPdpException { + _sender.sendDeleteRequestState(); + _status = ST_FINAL; + } + + /** + * Asks for a COPS sync + * @throws COPSPdpException + */ + protected void syncRequestState() + throws COPSPdpException { + _sender.sendSyncRequestState(); + _status = ST_SYNC; + } + + /** + * Opens a new request state + * @throws COPSPdpException + */ + protected void openNewRequestState()//FIXME: unused? + throws COPSPdpException { + _sender.sendOpenNewRequestState(); + _status = ST_NEW; + } + + /** + * Processes a COPS delete message + * @param dMsg COPSDeleteMsg received from the PEP + * @throws COPSPdpException + */ + protected void processDeleteRequestState(COPSDeleteMsg dMsg) + throws COPSPdpException { + if (_process != null) + _process.closeRequestState(this); + + _status = ST_DEL; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepException.java b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepException.java new file mode 100644 index 0000000..6f3fde7 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepException.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.ospep; + +/** + * COPS PEP Exception + * + * @version COPSPepException.java, v 2.00 2004 + * + */ +public class COPSPepException extends Exception { + + private int rc; + final static int GENERAL_ERROR = 0x00000001; + + /** + * Creates a COPSPdpException with the given message. + * @param msg Exception message + */ + + public COPSPepException(String msg) { + super(msg); + rc=0; + } + + /** + * Creates a COPSPdpException with the given message and return code. + * @param msg Exception message + * @param retCode Return code + */ + public COPSPepException(String msg, int retCode) { + super(msg); + rc = retCode; + } + + /** + * Returns the return code of the exception + * + * @return Exception's return code + * + */ + public int returnCode() { + return rc; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSAgent.java b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSAgent.java new file mode 100644 index 0000000..9c80a38 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSAgent.java @@ -0,0 +1,329 @@ +package org.umu.cops.ospep; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.Hashtable; +import java.util.Vector; + +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSTransceiver; + +/** + * This is a outsourcing COPS PEP. Responsible for making + * connection to the PDP and maintaining it + */ +public class COPSPepOSAgent { + /** + PEP's identifier + */ + private String _pepID; + + /** + PEP's client-type + */ + private short _clientType; + + /** + PDP host name + */ + private String _psHost; + + /** + PDP port + */ + private int _psPort; + + /** + PEP-PDP connection manager + */ + private COPSPepOSConnection _conn; + + /** + COPS error returned by the PDP + */ + private COPSError _error; + + /** + * Policy data processor class + */ + private COPSPepOSDataProcess _process; + + /** + * Creates a PEP agent + * @param pepID PEP-ID + * @param clientType Client-type + */ + public COPSPepOSAgent(String pepID, short clientType) { + _pepID = pepID; + _clientType = clientType; + } + + /** + * Creates a PEP agent with a PEP-ID equal to "noname" + * @param clientType Client-type + */ + public COPSPepOSAgent(short clientType) { + // PEPId + try { + _pepID = InetAddress.getLocalHost().getHostName(); + } catch (Exception e) { + _pepID = "noname"; + } + + _clientType = clientType; + } + + /** + * Gets the identifier of the PEP + * @return PEP-ID + */ + public String getPepID() { + return _pepID; + } + + /** + * Sets the policy data processor + * @param aDataProcess Data processor class + */ + public void setDataProcess(COPSPepOSDataProcess aDataProcess) { + this._process = aDataProcess; + } + + /** + * Gets the COPS client-type + * @return PEP's client-type + */ + public short getClientType() { + return _clientType; + } + + /** + * Gets PDP host name + * @return PDP host name + */ + public String getPDPName() { + return _psHost; + } + + /** + * Gets the port of the PDP + * @return PDP port + */ + public int getPDPPort() { + return _psPort; + } + + /** + * Connects to a PDP + * @param psHost PDP host name + * @param psPort PDP port + * @return true if PDP accepts the connection; false otherwise + * @throws java.net.UnknownHostException + * @throws java.io.IOException + * @throws COPSException + * @throws COPSPepException + */ + public boolean connect(String psHost, int psPort) throws UnknownHostException, IOException, COPSException, COPSPepException { + // COPSDebug.out(getClass().getName(), "Thread ( " + _pepID + ") - Connecting to PDP"); + _psHost = psHost; + _psPort = psPort; + + // Check whether it already exists + if (_conn == null) + _conn = processConnection(psHost,psPort); + else { + // Check whether it's closed + if (_conn.isClosed()) + _conn = processConnection(psHost,psPort); + else { + disconnect(null); + _conn = processConnection(psHost,psPort); + } + } + + return (_conn != null); + } + + /** + * Gets the connection manager + * @return PEP-PDP connection manager object + */ + public COPSPepOSConnection getConnection() { + return (_conn); + } + + /** + * Gets the COPS error returned by the PDP + * @return COPSError returned by PDP + */ + public COPSError getConnectionError() { + return _error; + } + + /** + * Disconnects from the PDP + * @param error Reason + * @throws COPSException + * @throws IOException + */ + public void disconnect(COPSError error) throws COPSException, IOException { + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, _clientType); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + if (error != null) + closeMsg.add(error); + + closeMsg.writeData(_conn.getSocket()); + _conn.close(); + _conn = null; + } + + /** + * Adds a request state to the connection manager. + * @param clientSIs The client data from the outsourcing event + * @return The newly created connection manager + * @throws COPSPepException + * @throws COPSException + */ + public COPSPepOSReqStateMan addRequestState(COPSHandle handle, Vector clientSIs) throws COPSPepException, COPSException { + if (_conn != null) + return _conn.addRequestState(handle.getId().str(), _process, clientSIs); + + return null; + } + + /** + * Queries the connection manager to delete a request state + * @param man Request state manager + * @throws COPSPepException + * @throws COPSException + */ + public void deleteRequestState (COPSPepOSReqStateMan man) throws COPSPepException, COPSException { + if (_conn != null) + _conn.deleteRequestState(man); + } + + /** + * Gets all the request state managers + * @return A Hashtable holding all active request state managers + */ + public Hashtable getReqStateMans() { + if (_conn != null) + return _conn.getReqStateMans(); + return null; + } + + /** + * Establish connection to PDP's IP address + * + * ::= + * + * [] + * [] + * [] + * + * Not support [], [], [] + * + * ::= + * + * [] + * [] + * + * Not send [] + * + * ::= + * + * [] + * [] + * + * Not send [], [] + * + * @throws UnknownHostException + * @throws IOException + * @throws COPSException + * @throws COPSPepException + * + */ + private COPSPepOSConnection processConnection(String psHost, int psPort) throws UnknownHostException, IOException, COPSException, COPSPepException { + // Build OPN + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_OPN, _clientType); + + COPSPepId pepId = new COPSPepId(); + COPSData d = new COPSData(_pepID); + pepId.setData(d); + + COPSClientOpenMsg msg = new COPSClientOpenMsg(); + msg.add(hdr); + msg.add(pepId); + + // Create socket and send OPN + InetAddress addr = InetAddress.getByName(psHost); + Socket socket = new Socket(addr,psPort); + msg.writeData(socket); + + // Get response + COPSMsg recvmsg = COPSTransceiver.receiveMsg(socket); + + if (recvmsg.getHeader().isAClientAccept()) { + COPSClientAcceptMsg cMsg = (COPSClientAcceptMsg) recvmsg; + + // Support + if (cMsg.getIntegrity() != null) { + throw new COPSPepException("Unsupported object (Integrity)"); + } + + // Mandatory KATimer + COPSKATimer kt = cMsg.getKATimer(); + if (kt == null) + throw new COPSPepException ("Mandatory COPS object missing (KA Timer)"); + short _kaTimeVal = kt.getTimerVal(); + + // ACTimer + COPSAcctTimer at = cMsg.getAcctTimer(); + short _acctTimer = 0; + if (at != null) + _acctTimer = at.getTimerVal(); + + // Create connection manager + COPSPepOSConnection conn = new COPSPepOSConnection(_clientType, socket); + conn.setKaTimer(_kaTimeVal); + conn.setAcctTimer(_acctTimer); + new Thread(conn).start(); + + return conn; + } else if (recvmsg.getHeader().isAClientClose()) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) recvmsg; + _error = cMsg.getError(); + socket.close(); + return null; + } else { // other message types are unexpected + throw new COPSPepException("Message not expected. Closing connection for " + socket.toString()); + } + } + + /** + * Creates a new request state when the outsourcing event is detected. + * @param handle The COPS handle for this request + * @param clientSIs The client specific data for this request + */ + public void dispatchEvent(COPSHandle handle, Vector clientSIs) { + try { + addRequestState(handle, clientSIs); + } catch (Exception e) { + System.err.println("COPSPepOSAgent: " + e.toString()); + } + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSConnection.java b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSConnection.java new file mode 100644 index 0000000..31a0b64 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSConnection.java @@ -0,0 +1,469 @@ +package org.umu.cops.ospep; + +import java.io.IOException; +import java.net.Socket; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKAMsg; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSSyncStateMsg; +import org.umu.cops.stack.COPSTransceiver; + +/** + * COPSPepConnection represents a PEP-PDP Connection Manager. + * Responsible for processing messages received from PDP. + */ +public class COPSPepOSConnection implements Runnable { + /** Socket connected to PDP */ + protected Socket _sock; + + /** Time to wait responses (milliseconds), default is 10 seconds */ + protected int _responseTime; + + /** COPS Client-type */ + protected short _clientType; + + /** + Accounting timer value (secs) + */ + protected short _acctTimer; + + /** + Keep-alive timer value (secs) + */ + protected short _kaTimer; + + /** + * Time of the latest keep-alive received + */ + protected Date _lastRecKa; + + /** + Opcode of the latest message sent + */ + protected byte _lastmessage; + + /** + Maps a COPS Client Handle to a Request State Manager + */ + protected Hashtable _managerMap; + // map < String(COPSHandle), COPSPepOSReqStateMan>; + + /** + COPS error returned by PDP + */ + protected COPSError _error; + + /** + * Creates a new PEP connection + * @param clientType PEP's client-type + * @param sock Socket connected to PDP + */ + public COPSPepOSConnection(short clientType, Socket sock) { + _clientType = clientType; + _sock = sock; + + // Timers + _acctTimer = 0; + _kaTimer = 0; + _responseTime = 10000; + _lastmessage = COPSHeader.COPS_OP_CAT; + + _managerMap = new Hashtable(20); + } + + /** + * Gets the response time + * @return Response time value (msecs) + */ + public int getResponseTime() { + return _responseTime; + } + + /** + * Gets the socket connected to the PDP + * @return Socket connected to PDP + */ + public Socket getSocket() { + return _sock; + } + + /** + * Gets keep-alive timer + * @return Keep-alive timer value (secs) + */ + public short getKaTimer () { + return _kaTimer; + } + + /** + * Gets accounting timer + * @return Accounting timer value (secs) + */ + public short getAcctTimer () { + return _acctTimer; + } + + /** + * Gets active COPS handles + * @return An Enumeration holding all active handles + */ + protected Enumeration getHandles() { + return _managerMap.keys(); + } + + /** + * Gets all request state managers + * @return A Hashatable holding all request state managers + */ + protected Hashtable getReqStateMans() { + return _managerMap; + } + + /** + * Checks whether the socket to the PDP is closed or not + * @return true if the socket is closed, false otherwise + */ + public boolean isClosed() { + return _sock.isClosed(); + } + + /** + * Closes the socket + * + * @throws java.io.IOException + */ + protected void close() throws IOException { + _sock.close(); + } + + /** + * Gets the opcode of the lastest message sent + * @return Message opcode + */ + public byte getLastmessage() { + return _lastmessage; + } + + /** + * Sets response time + * @param respTime Response time value (msecs) + */ + public void setResponseTime(int respTime) { + _responseTime = respTime; + }; + + /** + * Sets keep-alive timer + * @param kaTimer Keep-alive timer value (secs) + */ + public void setKaTimer(short kaTimer) { + _kaTimer = kaTimer; + } + + /** + * Sets accounting timer + * @param acctTimer Accounting timer value (secs) + */ + public void setAcctTimer(short acctTimer) { + _acctTimer = acctTimer; + } + + /** + * Message-processing loop + */ + public void run () { + Date _lastSendKa = new Date(); + Date _lastSendAcc = new Date(); + _lastRecKa = new Date(); + + try { + while (!_sock.isClosed()) { + if (_sock.getInputStream().available() != 0) { + _lastmessage = processMessage(_sock); + _lastRecKa = new Date(); + } + + // Keep Alive + if (_kaTimer > 0) { + // Timeout del PDP + int _startTime = (int) (_lastRecKa.getTime()); + int cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > _kaTimer*1000) { + _sock.close(); + // Notify all Request State Managers + notifyNoKAAllReqStateMan(); + } + + // Send to PEP + _startTime = (int) (_lastSendKa.getTime()); + cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > ((_kaTimer*3/4) * 1000)) { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA); + COPSKAMsg msg = new COPSKAMsg(); + + msg.add(hdr); + + COPSTransceiver.sendMsg(msg, _sock); + _lastSendKa = new Date(); + } + } + + // Accounting + if (_acctTimer > 0) { + int _startTime = (int) (_lastSendAcc.getTime()); + int cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > ((_acctTimer*3/4)*1000)) { + // Notify all Request State Managers + notifyAcctAllReqStateMan(); + _lastSendAcc = new Date(); + } + } + + try { + Thread.sleep(500); + } catch (Exception e) {}; + } + } catch (Exception e) { + e.printStackTrace(); + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } + + // connection closed by server + // COPSDebug.out(getClass().getName(),"Connection closed by server"); + try { + _sock.close(); + } catch (IOException e) {}; + + // Notify all Request State Managers + try { + notifyCloseAllReqStateMan(); + } catch (COPSPepException e) {}; + } + + /** + * Gets a COPS message from the socket and processes it + * @param conn Socket connected to the PDP + * @return COPS message type + * @throws COPSPepException + * @throws COPSException + * @throws IOException + */ + protected byte processMessage(Socket conn) throws COPSPepException, COPSException, IOException { + COPSMsg msg = COPSTransceiver.receiveMsg(conn); + + if (msg.getHeader().isAClientClose()) { + handleClientCloseMsg(conn, msg); + return COPSHeader.COPS_OP_CC; + } else if (msg.getHeader().isADecision()) { + handleDecisionMsg(/*OJO conn, */msg); + return COPSHeader.COPS_OP_DEC; + } else if (msg.getHeader().isASyncStateReq()) { + handleSyncStateReqMsg(conn, msg); + return COPSHeader.COPS_OP_SSQ; + } else if (msg.getHeader().isAKeepAlive()) { + handleKeepAliveMsg(conn, msg); + return COPSHeader.COPS_OP_KA; + } else { + throw new COPSPepException("Message not expected (" + msg.getHeader().getOpCode() + ")."); + } + } + + /** + * Handle Client Close Message, close the passed connection + * + * @param conn a Socket + * @param msg a COPSMsg + * + * + * ::= + * + * [] + * + * Not support [] + * + */ + private void handleClientCloseMsg(Socket conn, COPSMsg msg) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg; + _error = cMsg.getError(); + + // COPSDebug.out(getClass().getName(),"Got close request, closing connection " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]"); + + try { + // Support + if (cMsg.getIntegrity() != null) + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + + conn.close(); + } catch (Exception unae) { }; + } + + /** + * Gets the COPS error + * @return COPSError returned by PDP + */ + protected COPSError getError() { + return _error; + } + + /** + * Handle Keep Alive Message + * + * ::= + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleKeepAliveMsg(Socket conn, COPSMsg msg) { + COPSKAMsg cMsg = (COPSKAMsg) msg; + + // COPSDebug.out(getClass().getName(),"Get KAlive Msg"); + + try { + // Support + if (cMsg.getIntegrity() != null) + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + + // must we do anything else? + + } catch (Exception unae) { }; + } + + /** + * Method handleDecisionMsg + * + * ::= + * + * *() | + * [] + * ::= + * + * [] + * ::= NULLFlag + * ::= NULLDecision | Install | Remove + * ::= < | > + * ::= *( ) + * ::= *( | ) + * + * @param msg a COPSMsg + * + */ + private void handleDecisionMsg(/*OJO Socket conn, */COPSMsg msg) throws COPSPepException { + COPSDecisionMsg dMsg = (COPSDecisionMsg) msg; + COPSHandle handle = dMsg.getClientHandle(); + COPSPepOSReqStateMan manager = (COPSPepOSReqStateMan) _managerMap.get(handle.getId().str()); + manager.processDecision(dMsg); + } + + /** + * Method handleSyncStateReqMsg + * + * ::= + * [] + * [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleSyncStateReqMsg(Socket conn, COPSMsg msg) throws COPSPepException { + COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg; + // COPSHandle handle = cMsg.getClientHandle(); + // COPSHeader header = cMsg.getHeader(); + + // Support + if (cMsg.getIntegrity() != null) + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + + COPSPepOSReqStateMan manager = (COPSPepOSReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + + if (manager == null) + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + else + manager.processSyncStateRequest(cMsg); + } + + /** + * Adds a new request state + * @param clientHandle Client's handle + * @param process Policy data processing object + * @param clientSIs Client data from the outsourcing event + * @return The newly created request state manager + * @throws COPSException + * @throws COPSPepException + */ + protected COPSPepOSReqStateMan addRequestState(String clientHandle, COPSPepOSDataProcess process, Vector clientSIs) throws COPSException, COPSPepException { + COPSPepOSReqStateMan manager = new COPSPepOSReqStateMan(_clientType, clientHandle); + if (_managerMap.get(clientHandle) != null) + throw new COPSPepException("Duplicate Handle, rejecting " + clientHandle); + + manager.setDataProcess(process); + manager.setClientSI(clientSIs); + _managerMap.put(clientHandle, manager); + manager.initRequestState(_sock); + return manager; + } + + /** + * Deletes a request state + * @param manager Request state manager + * @throws COPSException + * @throws COPSPepException + */ + protected void deleteRequestState(COPSPepOSReqStateMan manager) throws COPSException, COPSPepException { + manager.finalizeRequestState(); + } + + private void notifyCloseAllReqStateMan() throws COPSPepException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPepOSReqStateMan man = (COPSPepOSReqStateMan) _managerMap.get(handle); + + man.processClosedConnection(_error); + } + } + } + + private void notifyNoKAAllReqStateMan() throws COPSPepException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPepOSReqStateMan man = (COPSPepOSReqStateMan) _managerMap.get(handle); + + man.processNoKAConnection(); + } + } + } + + private void notifyAcctAllReqStateMan() throws COPSPepException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPepOSReqStateMan man = (COPSPepOSReqStateMan) _managerMap.get(handle); + + man.processAcctReport(); + } + } + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSDataProcess.java b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSDataProcess.java new file mode 100644 index 0000000..1ee476b --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSDataProcess.java @@ -0,0 +1,59 @@ +package org.umu.cops.ospep; + +import java.util.Vector; + +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSError; + +/** + * Abstract class for implementing policy data processing classes for outsourcing PEPs. + */ +public abstract class COPSPepOSDataProcess { + /** + * Applies the decisions from the PDP + * @param man The request state manager + * @param dMsg The decisions message + * @return true if failed (reports indicate failure), false otherwise + */ + public abstract boolean setDecisions(COPSPepOSReqStateMan man, COPSDecisionMsg dMsg); + + /** + * Gets the report data + * @param man The request state manager + * @return A Vector holding the report data + */ + public abstract Vector getReportData(COPSPepOSReqStateMan man); + + /** + * Gets the supplied client data + * @param man The request state manager + * @return A Vector holding the client data + */ + public abstract Vector getClientData(COPSPepOSReqStateMan man); + + /** + * Gets the account data + * @param man The request state manager + * @return A Vector holding the account data + */ + public abstract Vector getAcctData(COPSPepOSReqStateMan man); + + /** + * Called when the connection is closed + * @param man The request state manager + * @param error Reason + */ + public abstract void notifyClosedConnection (COPSPepOSReqStateMan man, COPSError error); + + /** + * Called when the keep-alive message is not received + * @param man The request state manager + */ + public abstract void notifyNoKAliveReceived (COPSPepOSReqStateMan man); + + /** + * Process a PDP request to close a Request State + * @param man The request state manager + */ + public abstract void closeRequestState(COPSPepOSReqStateMan man); +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSEventListener.java b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSEventListener.java new file mode 100644 index 0000000..9266440 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSEventListener.java @@ -0,0 +1,30 @@ +package org.umu.cops.ospep; + +/** + * Abstract class for creating listeners for outsourcing events. + */ +public abstract class COPSPepOSEventListener extends Thread { + /** + * COPSPepOSAgent to be waked up upon event detection. + */ + protected COPSPepOSAgent _agent; + + /** + * Sets the COPS agent to be waked up. + * @param anAgent A COPSPepOSAgent + */ + public void setAgent(COPSPepOSAgent anAgent) { + _agent = anAgent; + } + + /** + * This must implement event detection, and wake up + * the COPS agent when it occurs. The steps are: + *
    + *
  • Detect the outsourcing event
  • + *
  • Build a Vector clientSIs from the event
  • + *
  • Generate a COPSHandle handle for the request
  • + *
  • Invoke _agent.dispatchEvent(handle, clientSIs)
+ */ + public abstract void run(); +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSMsgSender.java b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSMsgSender.java new file mode 100644 index 0000000..2f8526e --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSMsgSender.java @@ -0,0 +1,261 @@ +package org.umu.cops.ospep; + +import java.io.IOException; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Vector; + +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSReason; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReportType; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * COPS message transceiver class for outsourcing connections at the PEP side. + */ +public class COPSPepOSMsgSender { + /** + * Socket connection to PDP + */ + protected Socket _sock; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + * Creates a COPSPepMsgSender + * + * @param clientType Client-type + * @param clientHandle Client handle + * @param sock Socket connected to the PDP + */ + public COPSPepOSMsgSender (short clientType, COPSHandle clientHandle, Socket sock) { + // COPS Handle + _handle = clientHandle; + _clientType = clientType; + + _sock = sock; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the client-type + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Sends a request to the PDP. + * The PEP establishes a request state client handle for which the + * remote PDP may maintain state. + * @param clientSIs Client data + * @throws COPSPepException + */ + public void sendRequest(Vector clientSIs) throws COPSPepException { + // Create COPS Message + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_REQ, _clientType); + + COPSContext cntxt = new COPSContext(COPSContext.CONFIG , (short) 0); + + COPSHandle handle = _handle; + + COPSReqMsg msg = new COPSReqMsg(); + try { + msg.add(hdr) ; + msg.add(handle) ; + msg.add(cntxt) ; + + Enumeration clientSIEnum = clientSIs.elements(); + while (clientSIEnum.hasMoreElements()) + msg.add( (COPSClientSI) clientSIEnum.nextElement()); + } catch (COPSException e) { + throw new COPSPepException("Error making Request Msg, reason: " + e.getMessage()); + } + + // Send message + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the request, reason: " + e.getMessage()); + } + } + + /** + * Sends a failure report to the PDP. This report message notifies the PDP + * of failure when carrying out the PDP's decision, or when reporting + * an accounting related state change. + * @param clientSIs Report data + * @throws COPSPepException + */ + public void sendFailReport(Vector clientSIs) throws COPSPepException { + COPSReportMsg msg = new COPSReportMsg(); + // Report FAIL + try { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_RPT, _clientType); + COPSHandle hnd = _handle; + + COPSReportType report = new COPSReportType(COPSReportType.FAILURE); + + msg.add(hdr); + msg.add(hnd); + msg.add(report); + + Enumeration clientSIEnum = clientSIs.elements(); + while (clientSIEnum.hasMoreElements()) + msg.add( (COPSClientSI) clientSIEnum.nextElement()); + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the report, reason: " + e.getMessage()); + } + } + + /** + * Sends a success report to the PDP. This report message notifies the PDP + * of success when carrying out the PDP's decision, or when reporting + * an accounting related state change. + * @param clientSIs Report data + * @throws COPSPepException + */ + public void sendSuccessReport(Vector clientSIs) throws COPSPepException { + COPSReportMsg msg = new COPSReportMsg(); + // Report SUCESS + try { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_RPT, _clientType); + COPSHandle hnd = _handle; + + COPSReportType report = new COPSReportType(COPSReportType.SUCCESS); + + msg.add(hdr); + msg.add(hnd); + msg.add(report); + + Enumeration clientSIEnum = clientSIs.elements(); + while (clientSIEnum.hasMoreElements()) + msg.add( (COPSClientSI) clientSIEnum.nextElement()); + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the report, reason: " + e.getMessage()); + } + } + + /** + * Sends an accounting report to the PDP + * @param clientSIs Report data + * @throws COPSPepException + */ + public void sendAcctReport(Vector clientSIs) throws COPSPepException { + COPSReportMsg msg = new COPSReportMsg(); + // Report SUCCESS + try { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_RPT, _clientType); + COPSHandle hnd = _handle; + + COPSReportType report = new COPSReportType(COPSReportType.ACCT); + + msg.add(hdr); + msg.add(hnd); + msg.add(report); + + Enumeration clientSIEnum = clientSIs.elements(); + while (clientSIEnum.hasMoreElements()) + msg.add( (COPSClientSI) clientSIEnum.nextElement()); + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the report, reason: " + e.getMessage()); + } + } + + /** + * Sends a sync-complete message to the PDP. This indicates the + * end of a synchronization requested by the PDP. + * @throws COPSPepException + */ + public void sendSyncComplete() throws COPSPepException { + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_SSC, _clientType); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = _handle; + + COPSSyncStateMsg msg = new COPSSyncStateMsg(); + try { + msg.add(hdr); + msg.add(clienthandle); + } catch (Exception e) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the sync state request, reason: " + e.getMessage()); + } + } + + /** + * Sends a delete request to the PDP. + * When sent from the PEP this message indicates to the remote PDP that + * the state identified by the client handle is no longer + * available/relevant. + * @throws COPSPepException + */ + public void sendDeleteRequest() throws COPSPepException { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DRQ, _clientType); + COPSHandle handle = _handle; + + // *** TODO: use real reason codes + COPSReason reason = new COPSReason((short) 234, (short) 345); + + COPSDeleteMsg msg = new COPSDeleteMsg(); + try { + msg.add(hdr); + msg.add(handle); + msg.add(reason); + msg.writeData(_sock); + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } catch (IOException e) { + throw new COPSPepException("Failed to send the delete request, reason: " + e.getMessage()); + } + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSReqStateMan.java b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSReqStateMan.java new file mode 100644 index 0000000..aab3bc1 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/ospep/COPSPepOSReqStateMan.java @@ -0,0 +1,308 @@ +package org.umu.cops.ospep; + +import java.net.Socket; +import java.util.Vector; + +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * State manager class for outsourcing requests, at the PEP side. + */ +public class COPSPepOSReqStateMan { + /** + * Request State created + */ + public final static short ST_CREATE = 1; + /** + * Request sent + */ + public final static short ST_INIT = 2; + /** + * Decisions received + */ + public final static short ST_DECS = 3; + /** + * Report sent + */ + public final static short ST_REPORT = 4; + /** + * Request State finalized + */ + public final static short ST_FINAL = 5; + /** + * New Request State solicited + */ + public final static short ST_NEW = 6; + /** + * Delete Request State solicited + */ + public final static short ST_DEL = 7; + /** + * SYNC request received + */ + public final static short ST_SYNC = 8; + /** + * Sync completed + */ + public final static short ST_SYNCALL = 9; + /** + * Close connection received + */ + public final static short ST_CCONN = 10; + /** + * Keep-alive timeout + */ + public final static short ST_NOKA = 11; + /** + * Accounting timeout + */ + public final static short ST_ACCT = 12; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + Object for performing policy data processing + */ + protected COPSPepOSDataProcess _process; + + /** + * ClientSI data from signaling. + */ + protected Vector _clientSIs; + + /** + * Current state of the request being managed + */ + protected short _status; + + /** + COPS message transceiver used to send COPS messages + */ + protected COPSPepOSMsgSender _sender; + + /** + * Sync state + */ + protected boolean _syncState; + + /** + * Creates a state request manager + * @param clientType Client-type + * @param clientHandle Client's COPSHandle + */ + public COPSPepOSReqStateMan(short clientType, String clientHandle) { + // COPS Handle + _handle = new COPSHandle(); + COPSData id = new COPSData(clientHandle); + _handle.setId(id); + // client-type + _clientType = clientType; + _syncState = true; + _status = ST_CREATE; + _clientSIs = null; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Sets the client SI data. + * @param someClientSIs Client SI data built by the event listener + */ + public void setClientSI(Vector someClientSIs) { + _clientSIs = someClientSIs; + } + + /** + * Gets the client-type + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Gets the request status + * @return Request status value + */ + public short getStatus() { + return _status; + } + + /** + * Gets the policy data processing object + * + * @return Policy data processing object + * + */ + public COPSPepOSDataProcess getDataProcess() { + return _process; + } + + /** + * Sets the policy data processing object + * + * @param process Policy data processing object + * + */ + public void setDataProcess(COPSPepOSDataProcess process) { + _process = process; + } + + /** + * Initializes a new request state over a socket + * @param sock Socket to the PDP + * @throws COPSPepException + */ + protected void initRequestState(Socket sock) throws COPSPepException { + // Inits an object for sending COPS messages to the PDP + _sender = new COPSPepOSMsgSender(_clientType, _handle, sock); + + // If an object exists for retrieving the PEP features, + // use it for retrieving them. + /* Hashtable clientSIs; + if (_process != null) + clientSIs = _process.getClientData(this); + else + clientSIs = null;*/ + + // Semd the request + _sender.sendRequest(_clientSIs); + + // Initial state + _status = ST_INIT; + } + + /** + * Deletes the request state + * @throws COPSPepException + */ + protected void finalizeRequestState() throws COPSPepException { + _sender.sendDeleteRequest(); + _status = ST_FINAL; + } + + /** + * Processes the decision message + * @param dMsg Decision message from the PDP + * @throws COPSPepException + */ + protected void processDecision(COPSDecisionMsg dMsg) throws COPSPepException { + // COPSDebug.out(getClass().getName(), "ClientId:" + getClientHandle().getId().str()); + + //Hashtable decisionsPerContext = dMsg.getDecisions(); + + //** Applies decisions to the configuration + //_process.setDecisions(this, removeDecs, installDecs, errorDecs); + // second param changed to dMsg so that the data processor + // can check the 'solicited' flag + boolean isFailReport = _process.setDecisions(this, dMsg /*decisionsPerContext*/); + _status = ST_DECS; + + if (isFailReport) { + // COPSDebug.out(getClass().getName(),"Sending FAIL Report\n"); + _sender.sendFailReport(_process.getReportData(this)); + } else { + // COPSDebug.out(getClass().getName(),"Sending SUCCESS Report\n"); + _sender.sendSuccessReport(_process.getReportData(this)); + } + _status = ST_REPORT; + + if (!_syncState) { + _sender.sendSyncComplete(); + _syncState = true; + _status = ST_SYNCALL; + } + } + + + /** + * Processes a COPS delete message + * @param dMsg COPSDeleteMsg received from the PDP + * @throws COPSPepException + */ + protected void processDeleteRequestState(COPSDecisionMsg dMsg) throws COPSPepException { + if (_process != null) + _process.closeRequestState(this); + + _status = ST_DEL; + } + + /** + * Processes the message SycnStateRequest. + * The message SycnStateRequest indicates that the remote PDP + * wishes the client (which appears in the common header) + * to re-send its state. + * + * @param ssMsg The sync request from the PDP + * + * @throws COPSPepException + * + */ + protected void processSyncStateRequest(COPSSyncStateMsg ssMsg) throws COPSPepException { + _syncState = false; + // If an object exists for retrieving the PEP features, + // use it for retrieving them. + + // Send the request + _sender.sendRequest(_clientSIs); + + _status = ST_SYNC; + } + + /** + * Called when connection is closed + * @param error Reason + * @throws COPSPepException + */ + protected void processClosedConnection(COPSError error) throws COPSPepException { + if (_process != null) + _process.notifyClosedConnection(this, error); + + _status = ST_CCONN; + } + + /** + * Called when no keep-alive is received + * @throws COPSPepException + */ + protected void processNoKAConnection() throws COPSPepException { + if (_process != null) + _process.notifyNoKAliveReceived(this); + + _status = ST_NOKA; + } + + /** + * Processes the accounting report + * @throws COPSPepException + */ + protected void processAcctReport() throws COPSPepException { + Vector report = new Vector(); + + if (_process != null) + report = _process.getAcctData(this); + + _sender.sendAcctReport(report); + + _status = ST_ACCT; + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpAgent.java b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpAgent.java new file mode 100644 index 0000000..b6043c6 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpAgent.java @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpdp; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSTransceiver; + +/** + * Core PDP agent for provisioning + */ +public class COPSPdpAgent extends Thread { + /** Well-known port for COPS */ + public static final int WELL_KNOWN_PDP_PORT = 3288; + /** Default keep-alive timer value (secs) */ + public static final short KA_TIMER_VALUE = 30; + /** Default accounting timer value (secs) */ + public static final short ACCT_TIMER_VALUE = 0; + + /** + PDP host IP + */ + private ServerSocket _serverSocket; + + /** + PDP host port + */ + private int _serverPort; + + /** + Client-type of connecting PEP + */ + private short _clientType; + + /** + Accounting timer (secs) + */ + private short _acctTimer; + + /** + Keep-alive timer (secs) + */ + private short _kaTimer; + + /** + Maps a PEP-ID to a connection + */ + private Hashtable _connectionMap; + // map < String(PEPID), COPSPdpConnection > ConnectionMap; + + /** + * Policy data processing object + */ + private COPSPdpDataProcess _process; + + /** + * Creates a PDP Agent + * + * @param clientType COPS Client-type + * @param process Object to perform policy data processing + */ + public COPSPdpAgent(short clientType, COPSPdpDataProcess process) { + _serverPort = WELL_KNOWN_PDP_PORT; + _kaTimer = KA_TIMER_VALUE; + _acctTimer = ACCT_TIMER_VALUE; + + _clientType = clientType; + _connectionMap = new Hashtable(40); + _process = process; + } + + /** + * Creates a PDP Agent + * + * @param port Port to listen to + * @param clientType COPS Client-type + * @param process Object to perform policy data processing + */ + public COPSPdpAgent(int port, short clientType, COPSPdpDataProcess process) { + _serverPort = port; + + _kaTimer = KA_TIMER_VALUE; + _acctTimer = ACCT_TIMER_VALUE; + + _clientType = clientType; + _connectionMap = new Hashtable(40); + _process = process; + } + + /** + * Sets the keep-alive timer value + * @param kaTimer Keep alive timer value (secs) + */ + public void setKaTimer (short kaTimer) { + _kaTimer = kaTimer; + } + + /** + * Sets the accounting timer value + * @param acctTimer Accounting timer value (secs) + */ + public void setAcctTimer (short acctTimer) { + _acctTimer = acctTimer; + } + + /** + * Gets the value of the keep-alive timer + * @return Keep-alive timer value (secs) + */ + public short getKaTimer () { + return _kaTimer; + } + + /** + * Gets the accounting timer value + * @return Accounting timer value (secs) + */ + public short getAcctTimer () { + return _acctTimer; + } + + /** + * Gets the PEPs connected to this PDP + * @return An Enumeration of all connected PEPs + */ + public Enumeration getConnectedPEPIds() { + return _connectionMap.keys(); + } + + /** + * Gets the connection map + * @return A Hashtable holding the connection map + */ + public Hashtable getConnectionMap() { + return _connectionMap; + } + + /** + * Gets the client-type + * @return The client-type + */ + public short getClientType() { + return _clientType; + } + + /** + * Disconnects a PEP + * @param pepID PEP-ID of the PEP to be disconnected + * @param error COPS Error to be reported as a reason + * @throws COPSException + * @throws IOException + */ + public void disconnect (String pepID, COPSError error) + throws COPSException, IOException { + + COPSPdpConnection pdpConn = (COPSPdpConnection) _connectionMap.get(pepID); + + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, _clientType); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + if (error != null) + closeMsg.add(error); + + closeMsg.writeData(pdpConn.getSocket()); + pdpConn.close(); + pdpConn = null; + } + + /** + * Requests a COPS sync for a PEP + * @param pepID PEP-ID of the PEP to be synced + * @throws COPSException + * @throws COPSPdpException + */ + public void sync (String pepID) + throws COPSException, COPSPdpException { + + COPSPdpConnection pdpConn = (COPSPdpConnection) _connectionMap.get(pepID); + pdpConn.syncAllRequestState(); + } + + /** + * Removes a PEP from the connection map + * @param pepID PEP-ID of the PEP to be removed + */ + public void delete (String pepID) { + _connectionMap.remove(pepID); + } + + + /** + * Runs the PDP process + */ + public void run() { + try { + _serverSocket = new ServerSocket (_serverPort); + + //Loop through for Incoming messages + + // server infinite loop + while (true) { + + // Wait for an incoming connection from a PEP + Socket socket = _serverSocket.accept(); + + // COPSDebug.out(getClass().getName(),"New connection accepted " + + // socket.getInetAddress() + + // ":" + socket.getPort()); + + // We're waiting for an OPN message + try { + COPSMsg msg = COPSTransceiver.receiveMsg(socket); + if (msg.getHeader().isAClientOpen()) { + handleClientOpenMsg(socket, msg); + } else { + // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + try { + socket.close(); + } catch (Exception ex) {}; + } + } catch (Exception e) { // COPSException, IOException + // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_EXCEPTION, + // "(" + socket.getInetAddress() + ":" + socket.getPort() + ")", e); + try { + socket.close(); + } catch (Exception ex) {}; + } + } + } catch (IOException e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + return; + } + } + + /** + * Handles a COPS client-open message + * @param conn Socket to the PEP + * @param msg COPSMsg holding the client-open message + * @throws COPSException + * @throws IOException + */ + private void handleClientOpenMsg(Socket conn, COPSMsg msg) + throws COPSException, IOException { + COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg; + COPSPepId pepId = cMsg.getPepId(); + + // Validate Client Type + if (msg.getHeader().getClientType() != _clientType) { + // Unsupported client type + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_UNSUPPORTED_CLIENT_TYPE, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) {} + + throw new COPSException("Unsupported client type"); + } + + // PEPId is mandatory + if (pepId == null) { + // Mandatory COPS object missing + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_MANDATORY_OBJECT_MISSING, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) {} + + throw new COPSException("Mandatory COPS object missing (PEPId)"); + } + + // Support + if ( (cMsg.getClientSI() != null) || + (cMsg.getPdpAddress() != null) || + (cMsg.getIntegrity() != null)) { + + // Unsupported objects + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); + COPSError err = new COPSError(COPSError.COPS_ERR_UNKNOWN_OBJECT, (short) 0); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + closeMsg.add(err); + try { + closeMsg.writeData(conn); + } catch (IOException unae) {} + + throw new COPSException("Unsupported objects (ClientSI, PdpAddress, Integrity)"); + } + + // Connection accepted + COPSHeader ahdr = new COPSHeader(COPSHeader.COPS_OP_CAT, msg.getHeader().getClientType()); + COPSKATimer katimer = new COPSKATimer(_kaTimer); + COPSAcctTimer acctTimer = new COPSAcctTimer(_acctTimer); + COPSClientAcceptMsg acceptMsg = new COPSClientAcceptMsg(); + acceptMsg.add(ahdr); + acceptMsg.add(katimer) ; + if (_acctTimer != 0) acceptMsg.add(acctTimer); + acceptMsg.writeData(conn); + + COPSPdpConnection pdpConn = new COPSPdpConnection(pepId,conn,_process); + pdpConn.setKaTimer(_kaTimer); + if (_acctTimer != 0) pdpConn.setAccTimer(_acctTimer); + new Thread(pdpConn).start(); + _connectionMap.put(pepId.getData().str(),pdpConn); + } + +} + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpConnection.java b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpConnection.java new file mode 100644 index 0000000..d1c011c --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpConnection.java @@ -0,0 +1,555 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpdp; + +import java.io.IOException; +import java.net.Socket; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKAMsg; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; +import org.umu.cops.stack.COPSTransceiver; + +/** + * Class for managing an provisioning connection at the PDP side. + */ +public class COPSPdpConnection implements Runnable { + + /** + Socket connected to PEP + */ + private Socket _sock; + + /** + PEP identifier + */ + private COPSPepId _pepId; + + /** + Time of the latest keep-alive sent + */ + private Date _lastKa; + + /** + Opcode of the latest message sent + */ + private byte _lastmessage; + + /** + * Time of the latest keep-alive received + */ + protected Date _lastRecKa; + + /** + Maps a Client Handle to a Handler + */ + protected Hashtable _managerMap; + // map < String(COPSHandle), COPSPdpHandler> HandlerMap; + + /** + * PDP policy data processor class + */ + protected COPSPdpDataProcess _process; + + /** + Accounting timer value (secs) + */ + protected short _acctTimer; + + /** + Keep-alive timer value (secs) + */ + protected short _kaTimer; + + /** + COPS error returned by PEP + */ + protected COPSError _error; + + /** + * Creates a new PDP connection + * + * @param pepId PEP-ID of the connected PEP + * @param sock Socket connected to PEP + * @param process Object for processing policy data + */ + public COPSPdpConnection(COPSPepId pepId, Socket sock, COPSPdpDataProcess process) { + _sock = sock; + _pepId = pepId; + + _lastKa = new Date(); + _lastmessage = COPSHeader.COPS_OP_OPN; + _managerMap = new Hashtable(20); + + _kaTimer = 0; + _process = process; + } + + /** + * Gets the time of that latest keep-alive sent + * @return Time of that latest keep-alive sent + */ + public Date getLastKAlive() { + return _lastKa; + } + + /** + * Sets the keep-alive timer value + * @param kaTimer Keep-alive timer value (secs) + */ + public void setKaTimer(short kaTimer) { + _kaTimer = kaTimer; + } + + /** + * Gets the keep-alive timer value + * @return Keep-alive timer value (secs) + */ + public short getKaTimer() { + return _kaTimer; + } + + /** + * Sets the accounting timer value + * @param acctTimer Accounting timer value (secs) + */ + public void setAccTimer(short acctTimer) { + _acctTimer = acctTimer; + } + + /** + * Gets the accounting timer value + * @return Accounting timer value (secs) + */ + public short getAcctTimer() { + return _acctTimer; + } + + /** + * Gets the latest COPS message + * @return Code of the latest message sent + */ + public byte getLastMessage() { + return _lastmessage; + } + + /** + * Gets active handles + * @return An Enumeration holding all active handles + */ + public Enumeration getHandles() { + return _managerMap.keys(); + } + + /** + * Gets the handle map + * @return A Hashtable holding the handle map + */ + public Hashtable getReqStateMans() { + return _managerMap; + } + + /** + * Gets the PEP-ID + * @return The ID of the PEP, as a String + */ + public String getPepId() { + return _pepId.getData().str(); + } + + /** + * Checks whether the socket to the PEP is closed or not + * @return true if closed, false otherwise + */ + public boolean isClosed() { + return _sock.isClosed(); + } + + /** + * Closes the socket to the PEP + * @throws IOException + */ + protected void close() + throws IOException { + _sock.close(); + } + + /** + * Gets the socket to the PEP + * @return Socket connected to the PEP + */ + public Socket getSocket() { + return _sock; + } + + /** + * Main loop + */ + public void run () { + Date _lastSendKa = new Date(); + _lastRecKa = new Date(); + try { + while (!_sock.isClosed()) { + if (_sock.getInputStream().available() != 0) { + _lastmessage = processMessage(_sock); + _lastRecKa = new Date(); + } + + // Keep Alive + if (_kaTimer > 0) { + // Timeout at PDP + int _startTime = (int) (_lastRecKa.getTime()); + int cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > _kaTimer*1000) { + _sock.close(); + // Notify all Request State Managers + notifyNoKAAllReqStateMan(); + } + + // Send to PEP + _startTime = (int) (_lastSendKa.getTime()); + cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > ((_kaTimer*3/4)*1000)) { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA); + COPSKAMsg msg = new COPSKAMsg(); + + msg.add(hdr); + + COPSTransceiver.sendMsg(msg, _sock); + _lastSendKa = new Date(); + } + } + + try { + Thread.sleep(500); + } catch (Exception e) {}; + + } + } catch (Exception e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } + + // connection closed by server + // COPSDebug.out(getClass().getName(),"Connection closed by client"); + try { + _sock.close(); + } catch (IOException e) {}; + + // Notify all Request State Managers + try { + notifyCloseAllReqStateMan(); + } catch (COPSPdpException e) {}; + } + + /** + * Gets a COPS message from the socket and processes it + * @param conn Socket connected to the PEP + * @return Type of COPS message + */ + private byte processMessage(Socket conn) + throws COPSPdpException, COPSException, IOException { + COPSMsg msg = COPSTransceiver.receiveMsg(conn); + + if (msg.getHeader().isAClientClose()) { + handleClientCloseMsg(conn, msg); + return COPSHeader.COPS_OP_CC; + } else if (msg.getHeader().isAKeepAlive()) { + handleKeepAliveMsg(conn, msg); + return COPSHeader.COPS_OP_KA; + } else if (msg.getHeader().isARequest()) { + handleRequestMsg(conn, msg); + return COPSHeader.COPS_OP_REQ; + } else if (msg.getHeader().isAReport()) { + handleReportMsg(conn, msg); + return COPSHeader.COPS_OP_RPT; + } else if (msg.getHeader().isADeleteReq()) { + handleDeleteRequestMsg(conn, msg); + return COPSHeader.COPS_OP_DRQ; + } else if (msg.getHeader().isASyncComplete()) { + handleSyncComplete(conn, msg); + return COPSHeader.COPS_OP_SSC; + } else { + throw new COPSPdpException("Message not expected (" + msg.getHeader().getOpCode() + ")."); + } + } + + /** + * Handle Client Close Message, close the passed connection + * + * @param conn a Socket + * @param msg a COPSMsg + * + * + * ::= + * + * [] + * + * Not support [] + * + */ + private void handleClientCloseMsg(Socket conn, COPSMsg msg) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg; + _error = cMsg.getError(); + + // COPSDebug.out(getClass().getName(),"Got close request, closing connection " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]"); + + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + conn.close(); + } catch (Exception unae) { }; + } + + /** + * Gets the occurred COPS Error + * @return COPSError object + */ + protected COPSError getError() { + return _error; + } + + /** + * Handle Keep Alive Message + * + * ::= + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleKeepAliveMsg(Socket conn, COPSMsg msg) { + COPSKAMsg cMsg = (COPSKAMsg) msg; + + COPSKAMsg kaMsg = (COPSKAMsg) msg; + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + kaMsg.writeData(conn); + } catch (Exception unae) { }; + } + + /** + * Handle Delete Request Message + * + * ::= + * + * + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleDeleteRequestMsg(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSDeleteMsg cMsg = (COPSDeleteMsg) msg; + // COPSDebug.out(getClass().getName(),"Removing ClientHandle for " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Reason " + cMsg.getReason().getDescription() + "]"); + + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + // Delete clientHandler + if (_managerMap.remove(cMsg.getClientHandle().getId().str()) == null) { + // COPSDebug.out(getClass().getName(),"Missing for ClientHandle " + + // cMsg.getClientHandle().getId().getData()); + } + + COPSPdpReqStateMan man = (COPSPdpReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processDeleteRequestState(cMsg); + } + + } + + /** + * Handle Request Message + * + * ::= + * + * + * *() + * [] + * ::= <*( )> + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleRequestMsg(Socket conn, COPSMsg msg) + throws COPSPdpException { + + COPSReqMsg reqMsg = (COPSReqMsg) msg; + COPSContext cntxt = reqMsg.getContext(); + COPSHeader header = reqMsg.getHeader(); + //short reqType = cntxt.getRequestType(); + short cType = header.getClientType(); + + // Support + if (reqMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + COPSPdpReqStateMan man; + man = (COPSPdpReqStateMan) _managerMap.get(reqMsg.getClientHandle().getId().str()); + if (man == null) { + + man = new COPSPdpReqStateMan(cType, reqMsg.getClientHandle().getId().str()); + _managerMap.put(reqMsg.getClientHandle().getId().str(),man); + man.setDataProcess(_process); + man.initRequestState(_sock); + + // COPSDebug.out(getClass().getName(),"createHandler called, clientType=" + + // header.getClientType() + " msgType=" + + // cntxt.getMessageType() + ", connId=" + conn.toString()); + } + + man.processRequest(reqMsg); + } + + /** + * Handle Report Message + * + * ::= + * + * + * *() + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleReportMsg(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSReportMsg repMsg = (COPSReportMsg) msg; + // COPSHandle handle = repMsg.getClientHandle(); + // COPSHeader header = repMsg.getHeader(); + + // Support + if (repMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + COPSPdpReqStateMan man = (COPSPdpReqStateMan) _managerMap.get(repMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processReport(repMsg); + } + } + + /** + * Method handleSyncComplete + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleSyncComplete(Socket conn, COPSMsg msg) + throws COPSPdpException { + COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg; + // COPSHandle handle = cMsg.getClientHandle(); + // COPSHeader header = cMsg.getHeader(); + + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + COPSPdpReqStateMan man = (COPSPdpReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + if (man == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + man.processSyncComplete(cMsg); + } + } + + /** + * Requests a COPS sync from the PEP + * @throws COPSException + * @throws COPSPdpException + */ + protected void syncAllRequestState() + throws COPSException, COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPdpReqStateMan man = (COPSPdpReqStateMan) _managerMap.get(handle); + + man.syncRequestState(); + } + } + } + + private void notifyCloseAllReqStateMan() + throws COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPdpReqStateMan man = (COPSPdpReqStateMan) _managerMap.get(handle); + + man.processClosedConnection(_error); + } + } + } + + private void notifyNoKAAllReqStateMan() + throws COPSPdpException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPdpReqStateMan man = (COPSPdpReqStateMan) _managerMap.get(handle); + + man.processNoKAConnection(); + } + } + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpDataProcess.java b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpDataProcess.java new file mode 100644 index 0000000..8491774 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpDataProcess.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpdp; + +import java.util.Hashtable; + +import org.umu.cops.stack.COPSError; + +/** + * Abstract class for implementing policy data processing classes for provisioning PDPs. + */ +abstract public class COPSPdpDataProcess { + /** + * Gets the policies to be uninstalled + * @param man The associated request state manager + * @return A Vector holding the policies to be uninstalled + */ + abstract public Hashtable getRemovePolicy(COPSPdpReqStateMan man); + /** + * Gets the policies to be installed + * @param man The associated request state manager + * @return A Vector holding the policies to be uninstalled + */ + abstract public Hashtable getInstallPolicy(COPSPdpReqStateMan man); + /** + * Makes a decision from the supplied request data + * @param man The associated request state manager + * @param reqSIs Client specific data suppplied in the COPS request + */ + abstract public void setClientData(COPSPdpReqStateMan man, Hashtable reqSIs); + /** + * Builds a failure report + * @param man The associated request state manager + * @param reportSIs Report data + */ + abstract public void failReport (COPSPdpReqStateMan man, Hashtable reportSIs); + /** + * Builds a success report + * @param man The associated request state manager + * @param reportSIs Report data + */ + abstract public void successReport (COPSPdpReqStateMan man, Hashtable reportSIs); + /** + * Builds an accounting report + * @param man The associated request state manager + * @param reportSIs Report data + */ + abstract public void acctReport (COPSPdpReqStateMan man, Hashtable reportSIs); + /** + * Notifies that no accounting report has been received + * @param man The associated request state manager + */ + public abstract void notifyNoAcctReport (COPSPdpReqStateMan man); + + /** + * Notifies a keep-alive timeout + * @param man The associated request state manager + */ + public abstract void notifyNoKAliveReceived (COPSPdpReqStateMan man); + + /** + * Notifies that the connection has been closed + * @param man The associated request state manager + * @param error Reason + */ + public abstract void notifyClosedConnection (COPSPdpReqStateMan man, COPSError error); + + /** + * Notifies that a request state has been deleted + * @param man The associated request state manager + */ + public abstract void notifyDeleteRequestState (COPSPdpReqStateMan man); + + /** + * Notifies that a request state has been closed + * @param man The associated request state manager + */ + public abstract void closeRequestState(COPSPdpReqStateMan man); +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpException.java b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpException.java new file mode 100644 index 0000000..fc4c74d --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpException.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpdp; + +/** + * Exception class for PDP errors + * + * @version COPSPdpException.java, v 2.00 2004 + * + */ + +public class COPSPdpException extends Exception { + + private int rc; + final static int GENERAL_ERROR = 0x00000001; + + /** + * Creates a COPSPdpException with the given message. + * @param msg Exception message + */ + public COPSPdpException(String msg) { + super(msg); + rc=0; + } + + /** + * Creates a COPSPdpException with the given message and return code. + * @param msg Exception message + * @param retCode Return code + */ + public COPSPdpException(String msg, int retCode) { + super(msg); + rc = retCode; + } + + /** + * Gets the return code of the exception + * @return Exception's return code + */ + public int returnCode() { + return rc; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpMsgSender.java b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpMsgSender.java new file mode 100644 index 0000000..a892b7f --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpMsgSender.java @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpdp; + +import java.io.IOException; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSPrEPD; +import org.umu.cops.stack.COPSPrID; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * COPS message transceiver class for provisioning connections at the PDP side. + */ +public class COPSPdpMsgSender { + + /** + * Socket connected to PEP + */ + protected Socket _sock; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + * Creates a COPSPepMsgSender + * + * @param clientType COPS client-type + * @param clientHandle Client handle + * @param sock Socket to the PEP + */ + public COPSPdpMsgSender (short clientType, COPSHandle clientHandle, Socket sock) { + // COPS Handle + _handle = clientHandle; + _clientType = clientType; + + _sock = sock; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the client-type + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Sends a decision message + * @param removeDecs Decisions to be removed + * @param installDecs Decisions to be installed + * @throws COPSPdpException + */ + public void sendDecision(Hashtable removeDecs, Hashtable installDecs) + throws COPSPdpException { + /* ::= + * + * *() | + * [] + * ::= + * + * [] + * ::= NULLFlag + * ::= NULLDecision | Install | Remove + * ::= < | > + * ::= *( ) + * ::= *( | ) + * + * Very important, this is actually being treated like this: + * ::= | + * ::= | + * + */ + + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_DEC, getClientType()); + hdr.setFlag(COPSHeader.COPS_FLAG_SOLICITED); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + handle.setId(getClientHandle().getId()); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + + // Remove Decisions + // + if (removeDecs.size() > 0) { + COPSDecision rdec1 = new COPSDecision(); + rdec1.setCmdCode(COPSDecision.DEC_REMOVE); + + decisionMsg.addDecision(rdec1, cntxt); + + for (Enumeration e = removeDecs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) removeDecs.get(strprid); + + // (PRID) + COPSDecision dec2 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + dec2.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + // (EPD) + COPSDecision dec3 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + dec3.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + decisionMsg.addDecision(dec2, cntxt); + decisionMsg.addDecision(dec3, cntxt); + } + } + + // Install Decisions + // + if (installDecs.size() > 0) { + COPSDecision idec1 = new COPSDecision(); + idec1.setCmdCode(COPSDecision.DEC_INSTALL); + + decisionMsg.addDecision(idec1, cntxt); + + for (Enumeration e = installDecs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) installDecs.get(strprid); + + // (PRID) + COPSDecision dec2 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + dec2.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + // (EPD) + COPSDecision dec3 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + dec3.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + decisionMsg.addDecision(dec2, cntxt); + decisionMsg.addDecision(dec3, cntxt); + } + + /** + COPSIntegrity intr = new COPSIntegrity(); + intr.setKeyId(19); + intr.setSeqNum(9); + intr.setKeyDigest(new COPSData("KEY DIGEST")); + decisionMsg.add(intr); + /**/ + } + } catch (COPSException e) { + throw new COPSPdpException("Error making Msg"); + } + + //** Send the decision + //** + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the decision, reason: " + e.getMessage()); + } + } + + /** + * Sends a decision message which was not requested by the PEP + * @param removeDecs Decisions to be removed + * @param installDecs Decisions to be installed + * @throws COPSPdpException + */ + public void sendUnsolicitedDecision(Hashtable removeDecs, Hashtable installDecs) + throws COPSPdpException { + //** Example of an UNSOLICITED decision + //** + + /* ::= + * + * *() | + * [] + * ::= + * + * [] + * ::= NULLFlag + * ::= NULLDecision | Install | Remove + * ::= < | > + * ::= *( ) + * ::= *( | ) + * + * Very important, this is actually being treated like this: + * ::= | + * ::= | + * + */ + + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle handle = new COPSHandle(); + handle.setId(getClientHandle().getId()); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(handle); + + // Decisions (no flags supplied) + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + + // Remove Decisions + // + COPSDecision rdec1 = new COPSDecision(); + rdec1.setCmdCode(COPSDecision.DEC_REMOVE); + + decisionMsg.addDecision(rdec1, cntxt); + + for (Enumeration e = removeDecs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) removeDecs.get(strprid); + + // (PRID) + COPSDecision dec2 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + dec2.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + // (EPD) + COPSDecision dec3 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + dec3.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + decisionMsg.addDecision(dec2, cntxt); + decisionMsg.addDecision(dec3, cntxt); + } + + // Install Decisions + // + COPSDecision idec1 = new COPSDecision(); + idec1.setCmdCode(COPSDecision.DEC_INSTALL); + + decisionMsg.addDecision(idec1, cntxt); + + for (Enumeration e = installDecs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) installDecs.get(strprid); + + // (PRID) + COPSDecision dec2 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + dec2.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + // (EPD) + COPSDecision dec3 = new COPSDecision(COPSDecision.DEC_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + dec3.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + decisionMsg.addDecision(dec2, cntxt); + decisionMsg.addDecision(dec3, cntxt); + } + + /** + COPSIntegrity intr = new COPSIntegrity(); + intr.setKeyId(19); + intr.setSeqNum(9); + intr.setKeyDigest(new COPSData("KEY DIGEST")); + decisionMsg.add(intr); + /**/ + } catch (COPSException e) { + throw new COPSPdpException("Error making Msg"); + } + + //** Send the decision + //** + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the decision, reason: " + e.getMessage()); + } + } + + /** + * Sends a message asking that the request state be deleted + * @throws COPSPdpException + */ + public void sendDeleteRequestState() + throws COPSPdpException { + /* ::= + * + * *() + * [] + * ::= + * + * ::= Remove Request-State + * + */ + + // Common Header with the same ClientType as the request (default UNSOLICITED) + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + // Decisions + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + // + COPSDecision dec = new COPSDecision(); + dec.setCmdCode(COPSDecision.DEC_REMOVE); + dec.setFlags(COPSDecision.F_REQSTATE); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(clienthandle); + decisionMsg.addDecision(dec, cntxt); + } catch (COPSException e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the open new request state, reason: " + e.getMessage()); + } + } + + /** + * Sends a request asking that a new request state be created + * @throws COPSPdpException + */ + public void sendOpenNewRequestState() + throws COPSPdpException { + /* ::= + * + * *() + * [] + * ::= + * + * ::= Install Request-State + * + */ + + // Common Header with the same ClientType as the request (default UNSOLICITED) + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_DEC, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + // Decisions + // + COPSContext cntxt = new COPSContext(COPSContext.CONFIG, (short) 0); + // + COPSDecision dec = new COPSDecision(); + dec.setCmdCode(COPSDecision.DEC_INSTALL); + dec.setFlags(COPSDecision.F_REQSTATE); + + COPSDecisionMsg decisionMsg = new COPSDecisionMsg(); + try { + decisionMsg.add(hdr); + decisionMsg.add(clienthandle); + decisionMsg.addDecision(dec, cntxt); + } catch (COPSException e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + decisionMsg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the open new request state, reason: " + e.getMessage()); + } + } + + /** + * Sends a message asking for a COPS sync operation + * @throws COPSPdpException + */ + public void sendSyncRequestState() + throws COPSPdpException { + /* ::= + * [] + * [] + */ + + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_SSQ, getClientType()); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = new COPSHandle(); + clienthandle.setId(_handle.getId()); + + COPSSyncStateMsg msg = new COPSSyncStateMsg(); + try { + msg.add(hdr); + msg.add(clienthandle); + } catch (Exception e) { + throw new COPSPdpException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPdpException("Failed to send the sync state request, reason: " + e.getMessage()); + } + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpReqStateMan.java b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpReqStateMan.java new file mode 100644 index 0000000..0698951 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpdp/COPSPdpReqStateMan.java @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpdp; + +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSPrObjBase; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReportType; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * State manager class for provisioning requests, at the PDP side. + */ +public class COPSPdpReqStateMan { + + /** + * Request State created + */ + public final static short ST_CREATE = 1; + /** + * Request received + */ + public final static short ST_INIT = 2; + /** + * Decisions sent + */ + public final static short ST_DECS = 3; + /** + * Report received + */ + public final static short ST_REPORT = 4; + /** + * Request State finalized + */ + public final static short ST_FINAL = 5; + /** + * New Request State solicited + */ + public final static short ST_NEW = 6; + /** + * Delete Request State solicited + */ + public final static short ST_DEL = 7; + /** + * SYNC request sent + */ + public final static short ST_SYNC = 8; + /** + * SYNC completed + */ + public final static short ST_SYNCALL = 9; + /** + * Close connection received + */ + public final static short ST_CCONN = 10; + /** + * Keep-alive timeout + */ + public final static short ST_NOKA = 11; + /** + * Accounting timeout + */ + public final static short ST_ACCT = 12; + + /** + * COPS client-type that identifies the policy client + */ + protected short _clientType; + + /** + * COPS client handle used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + * Object for performing policy data processing + */ + protected COPSPdpDataProcess _process; + + /** + * Current state of the request being managed + */ + protected short _status; + + /** COPS message transceiver used to send COPS messages */ + protected COPSPdpMsgSender _sender; + + /** + * Creates a request state manager + * @param clientType Client-type + * @param clientHandle Client handle + */ + public COPSPdpReqStateMan(short clientType, String clientHandle) { + // COPS Handle + _handle = new COPSHandle(); + COPSData id = new COPSData(clientHandle); + _handle.setId(id); + // client-type + _clientType = clientType; + + _status = ST_CREATE; + } + + /** + * Gets the client handle + * @return Client's COPSHandle + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Gets the client-type + * @return Client-type value + */ + public short getClientType() { + return _clientType; + } + + /** + * Gets the status of the request + * @return Request state value + */ + public short getStatus() { + return _status; + } + + /** + * Gets the policy data processing object + * @return Policy data processing object + */ + public COPSPdpDataProcess getDataProcess() { + return _process; + } + + /** + * Sets the policy data processing object + * @param process Policy data processing object + */ + public void setDataProcess(COPSPdpDataProcess process) { + _process = process; + } + + /** + * Called when COPS sync is completed + * @param repMsg COPS sync message + * @throws COPSPdpException + */ + protected void processSyncComplete(COPSSyncStateMsg repMsg) + throws COPSPdpException { + + _status = ST_SYNCALL; + + // maybe we should notifySyncComplete ... + } + + /** + * Initializes a new request state over a socket + * @param sock Socket to the PEP + * @throws COPSPdpException + */ + protected void initRequestState(Socket sock) + throws COPSPdpException { + // Inits an object for sending COPS messages to the PEP + _sender = new COPSPdpMsgSender(_clientType, _handle, sock); + + // Initial state + _status = ST_INIT; + } + + /** + * Processes a COPS request + * @param msg COPS request received from the PEP + * @throws COPSPdpException + */ + protected void processRequest(COPSReqMsg msg) + throws COPSPdpException { + + COPSHeader hdrmsg = msg.getHeader(); + COPSHandle handlemsg = msg.getClientHandle(); + COPSContext contextmsg = msg.getContext(); + + //** Analyze the request + //** + + /* ::= + * + * + * *() + * [] + * ::= <*( )> + * + * Very important, this is actually being treated like this: + * ::= | + * + + // Named ClientSI + Vector clientSIs = msg.getClientSI(); + Hashtable reqSIs = new Hashtable(40); + String strobjprid = new String(); + for (Enumeration e = clientSIs.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + + COPSPrObjBase obj = new COPSPrObjBase(clientSI.getData().getData()); + switch (obj.getSNum()) + { + case COPSPrObjBase.PR_PRID: + strobjprid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + reqSIs.put(strobjprid, obj.getData().str()); + // COPSDebug.out(getClass().getName(),"PRID: " + strobjprid); + // COPSDebug.out(getClass().getName(),"EPD: " + obj.getData().str()); + break; + default: + break; + } + } + + //** Here we must retrieve a decision depending on + //** the supplied ClientSIs + // reqSIs is a hashtable with the prid and epds + + // ................ + // + Hashtable removeDecs = new Hashtable(); + Hashtable installDecs = new Hashtable(); + _process.setClientData(this, reqSIs); + + removeDecs = _process.getRemovePolicy(this); + installDecs = _process.getInstallPolicy(this); + + //** We create the SOLICITED decision + //** + _sender.sendDecision(removeDecs, installDecs); + _status = ST_DECS; + */ + } + + /** + * Processes a report + * @param msg Report message from the PEP + * @throws COPSPdpException + */ + protected void processReport(COPSReportMsg msg) + throws COPSPdpException { + + //** Analyze the report + //** + + /* + * ::= + * + * + * *() + * [] + * ::= <[] *()> + * ::= *() + * + * Important, is not parsed + */ + + // COPSHeader hdrmsg = msg.getHeader(); + // COPSHandle handlemsg = msg.getClientHandle(); + + // Report Type + COPSReportType rtypemsg = msg.getReport(); + + // Named ClientSI + Vector clientSIs = msg.getClientSI(); + Hashtable repSIs = new Hashtable(40); + String strobjprid = new String(); + for (Enumeration e = clientSIs.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + + COPSPrObjBase obj = new COPSPrObjBase(clientSI.getData().getData()); + switch (obj.getSNum()) { + case COPSPrObjBase.PR_PRID: + strobjprid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + repSIs.put(strobjprid, obj.getData().str()); + // COPSDebug.out(getClass().getName(),"PRID: " + strobjprid); + // COPSDebug.out(getClass().getName(),"EPD: " + obj.getData().str()); + break; + default: + break; + } + } + + //** Here we must act in accordance with + //** the report received + if (rtypemsg.isSuccess()) { + _status = ST_REPORT; + _process.successReport(this, repSIs); + } else if (rtypemsg.isFailure()) { + _status = ST_REPORT; + _process.failReport(this, repSIs); + } else if (rtypemsg.isAccounting()) { + _status = ST_ACCT; + _process.acctReport(this, repSIs); + } + } + + /** + * Called when connection is closed + * @param error Reason + * @throws COPSPdpException + */ + protected void processClosedConnection(COPSError error) + throws COPSPdpException { + if (_process != null) + _process.notifyClosedConnection(this, error); + + _status = ST_CCONN; + } + + /** + * Called when no keep-alive is received + * @throws COPSPdpException + */ + protected void processNoKAConnection() + throws COPSPdpException { + if (_process != null) + _process.notifyNoKAliveReceived(this); + + _status = ST_NOKA; + } + + /** + * Deletes the request state + * @throws COPSPdpException + */ + protected void finalizeRequestState() + throws COPSPdpException { + _sender.sendDeleteRequestState(); + _status = ST_FINAL; + } + + /** + * Asks for a COPS sync + * @throws COPSPdpException + */ + protected void syncRequestState() + throws COPSPdpException { + _sender.sendSyncRequestState(); + _status = ST_SYNC; + } + + /** + * Opens a new request state + * @throws COPSPdpException + */ + protected void openNewRequestState() + throws COPSPdpException { + _sender.sendOpenNewRequestState(); + _status = ST_NEW; + } + + /** + * Processes a COPS delete message + * @param dMsg COPSDeleteMsg received from the PEP + * @throws COPSPdpException + */ + protected void processDeleteRequestState(COPSDeleteMsg dMsg) + throws COPSPdpException { + if (_process != null) + _process.closeRequestState(this); + + _status = ST_DEL; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepAgent.java b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepAgent.java new file mode 100644 index 0000000..343d40c --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepAgent.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpep; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.Hashtable; + +import org.umu.cops.stack.COPSAcctTimer; +import org.umu.cops.stack.COPSClientAcceptMsg; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSClientOpenMsg; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKATimer; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSPepId; +import org.umu.cops.stack.COPSTransceiver; + +/** + * This is a provisioning COPS PEP. Responsible for making + * connection to the PDP and maintaining it + */ +public class COPSPepAgent { + + /** + PEP's Identifier + */ + private String _pepID; + + /** + PEP's client-type + */ + private short _clientType; + + /** + PDP host name + */ + private String _psHost; + + /** + PDP port + */ + private int _psPort; + + /** + PEP-PDP connection manager + */ + private COPSPepConnection _conn; + + /** + COPS error returned by PDP + */ + private COPSError _error; + + /** + * Creates a PEP agent + * @param pepID PEP-ID + * @param clientType Client-type + */ + public COPSPepAgent(String pepID, short clientType) { + _pepID = pepID; + _clientType = clientType; + } + + /** + * Creates a PEP agent with a PEP-ID equal to "noname" + * @param clientType Client-type + */ + public COPSPepAgent(short clientType) { + + // PEPId + try { + _pepID = InetAddress.getLocalHost().getHostName(); + } catch (Exception e) { + _pepID = "noname"; + } + + _clientType = clientType; + } + + /** + * Gets the identifier of the PEP + * @return PEP-ID + */ + public String getPepID() { + return _pepID; + } + + /** + * Gets the COPS client-type + * @return PEP's client-type + */ + public short getClientType() { + return _clientType; + } + + /** + * Gets PDP host name + * @return PDP host name + */ + public String getPDPName() { + return _psHost; + } + + /** + * Gets the port of the PDP + * @return PDP port + */ + public int getPDPPort() { + return _psPort; + } + + /** + * Connects to a PDP + * @param psHost PDP host name + * @param psPort PDP port + * @return true if PDP accepts the connection; false otherwise + * @throws java.net.UnknownHostException + * @throws java.io.IOException + * @throws COPSException + * @throws COPSPepException + */ + public boolean connect(String psHost, int psPort) + throws UnknownHostException, IOException, COPSException, COPSPepException { + + // COPSDebug.out(getClass().getName(), "Thread ( " + _pepID + ") - Connecting to PDP"); + _psHost = psHost; + _psPort = psPort; + + // Check whether it already exists + if (_conn == null) + _conn = processConnection(psHost,psPort); + else { + // Check if it's closed + if (_conn.isClosed()) { + _conn = processConnection(psHost,psPort); + } else { + disconnect(null); + _conn = processConnection(psHost,psPort); + } + } + + return (_conn != null); + } + + /** + * Gets the connection manager + * @return PEP-PDP connection manager object + */ + public COPSPepConnection getConnection () { + return (_conn); + } + + /** + * Gets the COPS error returned by the PDP + * @return COPSError returned by PDP + */ + public COPSError getConnectionError() { + return _error; + } + + /** + * Disconnects from the PDP + * @param error Reason + * @throws COPSException + * @throws IOException + */ + public void disconnect(COPSError error) + throws COPSException, IOException { + + COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, _clientType); + COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); + closeMsg.add(cHdr); + if (error != null) + closeMsg.add(error); + + closeMsg.writeData(_conn.getSocket()); + _conn.close(); + _conn = null; + } + + /** + * Adds a request state to the connection manager. + * @return The newly created connection manager + * @throws COPSPepException + * @throws COPSException + */ + public COPSPepReqStateMan addRequestState (String handle, COPSPepDataProcess process) + throws COPSPepException, COPSException { + if (_conn != null) { + return _conn.addRequestState(handle, process); + } + return null; + } + + + /** + * Queries the connection manager to delete a request state + * @param man Request state manager + * @throws COPSPepException + * @throws COPSException + */ + public void deleteRequestState (COPSPepReqStateMan man) + throws COPSPepException, COPSException { + if (_conn != null) + _conn.deleteRequestState(man); + } + + /** + * Gets all the request state managers + * @return A Hashtable holding all active request state managers + */ + public Hashtable getReqStateMans() { + if (_conn != null) + return _conn.getReqStateMans(); + return null; + } + + /** + * Establish connection to PDP's IP address + * + * ::= + * + * [] + * [] + * [] + * + * Not support [], [], [] + * + * ::= + * + * [] + * [] + * + * Not send [] + * + * ::= + * + * [] + * [] + * + * Not send [], [] + * + * @throws UnknownHostException + * @throws IOException + * @throws COPSException + * @throws COPSPepException + * + */ + private COPSPepConnection processConnection(String psHost, int psPort) + throws UnknownHostException, IOException, COPSException, COPSPepException { + // Build OPN + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_OPN, _clientType); + + COPSPepId pepId = new COPSPepId(); + COPSData d = new COPSData(_pepID); + pepId.setData(d); + + COPSClientOpenMsg msg = new COPSClientOpenMsg(); + msg.add(hdr); + msg.add(pepId); + + // Create Socket and send OPN + InetAddress addr = InetAddress.getByName(psHost); + Socket socket = new Socket(addr,psPort); + msg.writeData(socket); + + // Receive the response + COPSMsg recvmsg = COPSTransceiver.receiveMsg(socket); + + if (recvmsg.getHeader().isAClientAccept()) { + COPSClientAcceptMsg cMsg = (COPSClientAcceptMsg) recvmsg; + + // Support + if (cMsg.getIntegrity() != null) { + throw new COPSPepException("Unsupported object (Integrity)"); + } + + // Mandatory KATimer + COPSKATimer kt = cMsg.getKATimer(); + if (kt == null) + throw new COPSPepException ("Mandatory COPS object missing (KA Timer)"); + short _kaTimeVal = kt.getTimerVal(); + + // ACTimer + COPSAcctTimer at = cMsg.getAcctTimer(); + short _acctTimer = 0; + if (at != null) + _acctTimer = at.getTimerVal(); + + // Create the connection manager + COPSPepConnection conn = new COPSPepConnection(_clientType, socket); + conn.setKaTimer(_kaTimeVal); + conn.setAcctTimer(_acctTimer); + new Thread(conn).start(); + + return conn; + } else if (recvmsg.getHeader().isAClientClose()) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) recvmsg; + _error = cMsg.getError(); + socket.close(); + return null; + } else { // messages of other types are not expected + throw new COPSPepException("Message not expected. Closing connection for " + socket.toString()); + } + } +} + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepConnection.java b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepConnection.java new file mode 100644 index 0000000..0e888ce --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepConnection.java @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpep; + +import java.io.IOException; +import java.net.Socket; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.umu.cops.common.COPSDebug; +import org.umu.cops.stack.COPSClientCloseMsg; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSKAMsg; +import org.umu.cops.stack.COPSMsg; +import org.umu.cops.stack.COPSSyncStateMsg; +import org.umu.cops.stack.COPSTransceiver; + +/** + * COPSPepConnection represents a PEP-PDP Connection Manager. + * Responsible for processing messages received from PDP. + */ +public class COPSPepConnection implements Runnable { + + /** Socket connected to PDP */ + protected Socket _sock; + + /** Time to wait responses (milliseconds), default is 10 seconds */ + protected int _responseTime; + + /** COPS Client-type */ + protected short _clientType; + + /** + Accounting timer value (secs) + */ + protected short _acctTimer; + + /** + Keep-alive timer value (secs) + */ + protected short _kaTimer; + + /** + * Time of the latest keep-alive received + */ + protected Date _lastRecKa; + + /** + Opcode of the latest message sent + */ + protected byte _lastmessage; + + /** + Maps a COPS Client Handle to a Request State Manager + */ + protected Hashtable _managerMap; + // map < String(COPSHandle), COPSPepReqStateMan>; + + /** + COPS error returned by PDP + */ + protected COPSError _error; + + /** + * Creates a new PEP connection + * @param clientType PEP's client-type + * @param sock Socket connected to PDP + */ + public COPSPepConnection(short clientType, Socket sock) { + + _clientType = clientType; + _sock = sock; + + // Timers + _acctTimer = 0; + _kaTimer = 0; + _responseTime = 10000; + _lastmessage = COPSHeader.COPS_OP_CAT; + + _managerMap = new Hashtable(20); + } + + /** + * Gets the response time + * @return Response time value (msecs) + */ + public int getResponseTime() { + return _responseTime; + } + + /** + * Gets the socket connected to the PDP + * @return Socket connected to PDP + */ + public Socket getSocket() { + return _sock; + } + + /** + * Gets keep-alive timer + * @return Keep-alive timer value (secs) + */ + public short getKaTimer () { + return _kaTimer; + } + + /** + * Gets accounting timer + * @return Accounting timer value (secs) + */ + public short getAcctTimer () { + return _acctTimer; + } + + /** + * Gets active COPS handles + * @return An Enumeration holding all active handles + */ + protected Enumeration getHandles() { + return _managerMap.keys(); + } + + /** + * Gets all request state managers + * @return A Hashatable holding all request state managers + */ + protected Hashtable getReqStateMans() { + return _managerMap; + } + + /** + * Checks whether the socket to the PDP is closed or not + * @return true if the socket is closed, false otherwise + */ + public boolean isClosed() { + return _sock.isClosed(); + } + + /** + * Closes the socket + * + * @throws java.io.IOException + */ + protected void close() + throws IOException { + _sock.close(); + } + + /** + * Gets the opcode of the lastest message sent + * @return Message opcode + */ + public byte getLastmessage() { + return _lastmessage; + } + + /** + * Sets response time + * @param respTime Response time value (msecs) + */ + public void setResponseTime(int respTime) { + _responseTime = respTime; + }; + + /** + * Sets keep-alive timer + * @param kaTimer Keep-alive timer value (secs) + */ + public void setKaTimer (short kaTimer) { + _kaTimer = kaTimer; + } + + /** + * Sets accounting timer + * @param acctTimer Accounting timer value (secs) + */ + public void setAcctTimer (short acctTimer) { + _acctTimer = acctTimer; + } + + /** + * Message-processing loop + */ + public void run () { + Date _lastSendKa = new Date(); + Date _lastSendAcc = new Date(); + _lastRecKa = new Date(); + try { + while (!_sock.isClosed()) { + if (_sock.getInputStream().available() != 0) { + _lastmessage = processMessage(_sock); + _lastRecKa = new Date(); + } + + // Keep Alive + if (_kaTimer > 0) { + // Timeout at PDP + int _startTime = (int) (_lastRecKa.getTime()); + int cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > _kaTimer*1000) { + _sock.close(); + // Notify all Request State Managers + notifyNoKAAllReqStateMan(); + } + + // Send to PEP + _startTime = (int) (_lastSendKa.getTime()); + cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > ((_kaTimer*3/4) * 1000)) { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA); + COPSKAMsg msg = new COPSKAMsg(); + + msg.add(hdr); + + COPSTransceiver.sendMsg(msg, _sock); + _lastSendKa = new Date(); + } + } + + // Accounting + if (_acctTimer > 0) { + int _startTime = (int) (_lastSendAcc.getTime()); + int cTime = (int) (new Date().getTime()); + + if ((int)(cTime - _startTime) > ((_acctTimer*3/4)*1000)) { + // Notify all Request State Managers + notifyAcctAllReqStateMan(); + _lastSendAcc = new Date(); + } + } + + try { + Thread.sleep(500); + } catch (Exception e) {}; + } + } catch (Exception e) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); + } + + // connection closed by server + // COPSDebug.out(getClass().getName(),"Connection closed by server"); + try { + _sock.close(); + } catch (IOException e) {}; + + // Notify all Request State Managers + try { + notifyCloseAllReqStateMan(); + } catch (COPSPepException e) {}; + } + + /** + * Gets a COPS message from the socket and processes it + * @param conn Socket connected to the PDP + * @return COPS message type + * @throws COPSPepException + * @throws COPSException + * @throws IOException + */ + protected byte processMessage(Socket conn) + throws COPSPepException, COPSException, IOException { + COPSMsg msg = COPSTransceiver.receiveMsg(conn); + + if (msg.getHeader().isAClientClose()) { + handleClientCloseMsg(conn, msg); + return COPSHeader.COPS_OP_CC; + } else if (msg.getHeader().isADecision()) { + handleDecisionMsg(conn, msg); + return COPSHeader.COPS_OP_DEC; + } else if (msg.getHeader().isASyncStateReq()) { + handleSyncStateReqMsg(conn, msg); + return COPSHeader.COPS_OP_SSQ; + } else if (msg.getHeader().isAKeepAlive()) { + handleKeepAliveMsg(conn, msg); + return COPSHeader.COPS_OP_KA; + } else { + throw new COPSPepException("Message not expected (" + msg.getHeader().getOpCode() + ")."); + } + } + + /** + * Handle Client Close Message, close the passed connection + * + * @param conn a Socket + * @param msg a COPSMsg + * + * + * ::= + * + * [] + * + * Not support [] + * + */ + private void handleClientCloseMsg(Socket conn, COPSMsg msg) { + COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg; + _error = cMsg.getError(); + + // COPSDebug.out(getClass().getName(),"Got close request, closing connection " + + // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]"); + + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + conn.close(); + } catch (Exception unae) { }; + } + + /** + * Method getError + * + * @return a COPSError + * + */ + protected COPSError getError() { + return _error; + } + + /** + * Handle Keep Alive Message + * + * ::= + * [] + * + * Not support [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleKeepAliveMsg(Socket conn, COPSMsg msg) { + COPSKAMsg cMsg = (COPSKAMsg) msg; + + // COPSDebug.out(getClass().getName(),"Get KAlive Msg"); + + try { + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + // should we do anything else?? .... + + } catch (Exception unae) { }; + } + + /** + * Method handleDecisionMsg + * + * ::= + * + * *() | + * [] + * ::= + * + * [] + * ::= NULLFlag + * ::= NULLDecision | Install | Remove + * ::= < | > + * ::= *( ) + * ::= *( | ) + * + * Very important, this is actually being treated like this: + * ::= | + * ::= | + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleDecisionMsg(Socket conn, COPSMsg msg) + throws COPSPepException { + COPSDecisionMsg dMsg = (COPSDecisionMsg) msg; + COPSHandle handle = dMsg.getClientHandle(); + Hashtable decisions = dMsg.getDecisions(); + + for (Enumeration e = decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) decisions.get(context); + + Enumeration ee = v.elements(); + if (ee.hasMoreElements()) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + + // Get the associated manager + COPSPepReqStateMan manager = (COPSPepReqStateMan) _managerMap.get(handle.getId().str()); + if (manager == null) + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + + // Check message type + if (decision.getFlags() == COPSDecision.F_REQSTATE) { + if (decision.isRemoveDecision()) + // Delete Request State + manager.processDeleteRequestState(dMsg); + else + // Open new Request State + handleOpenNewRequestStateMsg(conn, handle); + } else + // Decision + manager.processDecision(dMsg); + } + } + } + + + /** + * Method handleOpenNewRequestStateMsg + * + * @param conn a Socket + * @param handle a COPSHandle + * + */ + private void handleOpenNewRequestStateMsg(Socket conn, COPSHandle handle) + throws COPSPepException { + + COPSPepReqStateMan manager = (COPSPepReqStateMan) _managerMap.get(handle.getId().str()); + if (manager == null) + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + + manager.processOpenNewRequestState(); + } + + /** + * Method handleSyncStateReqMsg + * + * ::= + * [] + * [] + * + * @param conn a Socket + * @param msg a COPSMsg + * + */ + private void handleSyncStateReqMsg(Socket conn, COPSMsg msg) + throws COPSPepException { + COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg; + // COPSHandle handle = cMsg.getClientHandle(); + // COPSHeader header = cMsg.getHeader(); + + // Support + if (cMsg.getIntegrity() != null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, + "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); + } + + COPSPepReqStateMan manager = (COPSPepReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); + if (manager == null) { + COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); + } else { + manager.processSyncStateRequest(cMsg); + } + } + + /** + * Method createRequestState + * + * @param clientHandle a String + * @param process a COPSPepDataProcess + * + * @return a COPSPepmanager + * + * @throws COPSException + * @throws COPSPepException + * + */ + protected COPSPepReqStateMan addRequestState(String clientHandle, COPSPepDataProcess process) + throws COPSException, COPSPepException { + COPSPepReqStateMan manager = new COPSPepReqStateMan(_clientType,clientHandle); + if (_managerMap.get(clientHandle) != null) + throw new COPSPepException("Duplicate Handle, rejecting " + clientHandle); + + manager.setDataProcess(process); + _managerMap.put(clientHandle,manager); + manager.initRequestState(_sock); + return manager; + } + + /** + * Method deleteRequestState + * + * @param manager a COPSPepReqStateMan + * + * @throws COPSException + * @throws COPSPepException + * + */ + protected void deleteRequestState(COPSPepReqStateMan manager) + throws COPSException, COPSPepException { + manager.finalizeRequestState(); + } + + private void notifyCloseAllReqStateMan() + throws COPSPepException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPepReqStateMan man = (COPSPepReqStateMan) _managerMap.get(handle); + + man.processClosedConnection(_error); + } + } + } + + private void notifyNoKAAllReqStateMan() + throws COPSPepException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPepReqStateMan man = (COPSPepReqStateMan) _managerMap.get(handle); + + man.processNoKAConnection(); + } + } + } + + private void notifyAcctAllReqStateMan() + throws COPSPepException { + if (_managerMap.size() > 0) { + for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { + String handle = (String) e.nextElement(); + COPSPepReqStateMan man = (COPSPepReqStateMan) _managerMap.get(handle); + + man.processAcctReport(); + } + } + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepDataProcess.java b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepDataProcess.java new file mode 100644 index 0000000..45d11dd --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepDataProcess.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpep; + +import java.util.Hashtable; + +import org.umu.cops.stack.COPSError; + +/** + * COPSPepDataProcess process policy data and events. + * + * @version COPSPepDataProcess.java, v 2.00 2004 + * + */ +public abstract class COPSPepDataProcess { + + /** + * Establish PDP decisions + * + * @param removeDecs + * @param installDecs + * @param errorDecs + */ + + public abstract void setDecisions(COPSPepReqStateMan man, Hashtable removeDecs, Hashtable installDecs, Hashtable errorDecs); + + /** + * If the report is fail, return true + * + * @return + */ + public abstract boolean isFailReport(COPSPepReqStateMan man); + + /** + * Return Report Data + * + * @return + */ + public abstract Hashtable getReportData(COPSPepReqStateMan man); + + /** + * Return Client Data + * + * @return + */ + public abstract Hashtable getClientData(COPSPepReqStateMan man); + + /** + * Return Accouting Data + * + * @return + */ + public abstract Hashtable getAcctData(COPSPepReqStateMan man); + + /** + * Notify the connection closed + * + * @param error + */ + public abstract void notifyClosedConnection (COPSPepReqStateMan man, COPSError error); + + /** + * Notify the KAlive timeout + */ + public abstract void notifyNoKAliveReceived (COPSPepReqStateMan man); + + /** + * Process a PDP request to close a Request State + * + * @param man Request State Manager + */ + public abstract void closeRequestState(COPSPepReqStateMan man); + + /** + * Process a PDP request to open a new Request State + * + * @param man + */ + public abstract void newRequestState(COPSPepReqStateMan man); +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepException.java b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepException.java new file mode 100644 index 0000000..ccac8ee --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpep; + +/** + * COPS PEP Exception + * + * @version COPSPepException.java, v 2.00 2004 + * + */ +public class COPSPepException extends Exception { + + private int rc; + final static int GENERAL_ERROR = 0x00000001; + + public COPSPepException(String s) { + super(s); + rc=0; + } + + public COPSPepException(String msg, int retCode) { + super(msg); + rc = retCode; + } + + /** + * Return error code + * + * @return error code + * + */ + public int returnCode() { + return rc; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepMsgSender.java b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepMsgSender.java new file mode 100644 index 0000000..010560c --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepMsgSender.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpep; + +import java.io.IOException; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.umu.cops.stack.COPSClientSI; +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDeleteMsg; +import org.umu.cops.stack.COPSException; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSHeader; +import org.umu.cops.stack.COPSPrEPD; +import org.umu.cops.stack.COPSPrID; +import org.umu.cops.stack.COPSReason; +import org.umu.cops.stack.COPSReportMsg; +import org.umu.cops.stack.COPSReportType; +import org.umu.cops.stack.COPSReqMsg; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * COPSPepMsgSender sends COPS messages to PDP. + * + * @version COPSPepMsgSender.java, v 2.00 2004 + * + */ +public class COPSPepMsgSender { + + /** + * Socket connection to PDP + */ + protected Socket _sock; + + /** + * The client-type identifies the policy client + */ + protected short _clientType; + + /** + * The client handle is used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + * Create a COPSPepMsgSender + * + * @param clientType client-type + * @param clientHandle client handle + * @param sock socket of PDP connection + */ + public COPSPepMsgSender (short clientType, COPSHandle clientHandle, Socket sock) { + // COPS Handle + _handle = clientHandle; + _clientType = clientType; + + _sock = sock; + } + + /** + * Return client handle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Return client-type + * + * @return a short + * + */ + public short getClientType() { + return _clientType; + } + + /** + * Send Request to PDP. + * The PEP establishes a request state client handle for which the + * remote PDP may maintain state. + * + * @param clientSIs a Hashtable + * + * @throws COPSPepException + * + */ + public void sendRequest(Hashtable clientSIs) + throws COPSPepException { + // Create COPS Message + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_REQ, _clientType); + COPSContext cntxt = new COPSContext(COPSContext.CONFIG , (short) 0); + + COPSHandle handle = _handle; + + // Add the clientSIs + COPSReqMsg msg = new COPSReqMsg(); + try { + msg.add(hdr) ; + msg.add(handle) ; + msg.add(cntxt) ; + + if (clientSIs.size() > 0) { + for (Enumeration e = clientSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) clientSIs.get(strprid); + + // (PRID) + COPSClientSI cSi = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + cSi.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + + // (EPD) + COPSClientSI cSi2 = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + cSi2.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + msg.add(cSi); + msg.add(cSi2); + } + } + + } catch (COPSException e) { + throw new COPSPepException("Error making Request Msg, reason: " + e.getMessage()); + } + + // Send message + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the request, reason: " + e.getMessage()); + } + } + + /** + * Send Fail Report to PDP. + * The RPT message is used by the PEP to communicate to the PDP its + * success or failure in carrying out the PDP's decision, or to report + * an accounting related change in state. + * + * @throws COPSPepException + * + */ + public void sendFailReport(Hashtable clientSIs) + throws COPSPepException { + COPSReportMsg msg = new COPSReportMsg(); + // Report FAIL + try { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_RPT, _clientType); + COPSHandle hnd = _handle; + + COPSReportType report = new COPSReportType(COPSReportType.FAILURE); + + msg.add(hdr); + msg.add(hnd); + msg.add(report); + if (clientSIs.size() > 0) { + for (Enumeration e = clientSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) clientSIs.get(strprid); + + // (PRID) + COPSClientSI cSi = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + cSi.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + + // (EPD) + COPSClientSI cSi2 = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + cSi2.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + msg.add(cSi); + msg.add(cSi2); + } + } + + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the report, reason: " + e.getMessage()); + } + } + + /** + * Send Succes Report to PDP. + * The RPT message is used by the PEP to communicate to the PDP its + * success or failure in carrying out the PDP's decision, or to report + * an accounting related change in state. + * + * @throws COPSPepException + * + */ + public void sendSuccessReport(Hashtable clientSIs) + throws COPSPepException { + COPSReportMsg msg = new COPSReportMsg(); + // Report SUCESS + try { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_RPT, _clientType); + COPSHandle hnd = _handle; + + COPSReportType report = new COPSReportType(COPSReportType.SUCCESS); + + msg.add(hdr); + msg.add(hnd); + msg.add(report); + + if (clientSIs.size() > 0) { + for (Enumeration e = clientSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) clientSIs.get(strprid); + + // (PRID) + COPSClientSI cSi = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + cSi.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + + // (EPD) + COPSClientSI cSi2 = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + cSi2.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + msg.add(cSi); + msg.add(cSi2); + } + } + + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the report, reason: " + e.getMessage()); + } + } + + public void sendAcctReport(Hashtable clientSIs) + throws COPSPepException { + COPSReportMsg msg = new COPSReportMsg(); + // Report SUCESS + try { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_RPT, _clientType); + COPSHandle hnd = _handle; + + COPSReportType report = new COPSReportType(COPSReportType.ACCT); + + msg.add(hdr); + msg.add(hnd); + msg.add(report); + + if (clientSIs.size() > 0) { + for (Enumeration e = clientSIs.keys() ; e.hasMoreElements() ;) { + String strprid = (String) e.nextElement(); + String strepd = (String) clientSIs.get(strprid); + + // (PRID) + COPSClientSI cSi = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrID prid = new COPSPrID(); + prid.setData(new COPSData(strprid)); + cSi.setData(new COPSData(prid.getDataRep(), 0, prid.getDataLength())); + + // (EPD) + COPSClientSI cSi2 = new COPSClientSI(COPSClientSI.CSI_NAMED); + COPSPrEPD epd = new COPSPrEPD(); + epd.setData(new COPSData(strepd)); + cSi2.setData(new COPSData(epd.getDataRep(), 0, epd.getDataLength())); + + msg.add(cSi); + msg.add(cSi2); + } + } + + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the report, reason: " + e.getMessage()); + } + } + + /** + * Send Sync State Complete to PDP. + * The Synchronize State Complete is sent by the PEP to the PDP after + * the PDP sends a synchronize state request to the PEP and the PEP has + * finished synchronization. + * + * @throws COPSPepException + * + */ + public void sendSyncComplete() + throws COPSPepException { + // Common Header with the same ClientType as the request + COPSHeader hdr = new COPSHeader (COPSHeader.COPS_OP_SSC, _clientType); + + // Client Handle with the same clientHandle as the request + COPSHandle clienthandle = _handle; + + COPSSyncStateMsg msg = new COPSSyncStateMsg(); + try { + msg.add(hdr); + msg.add(clienthandle); + } catch (Exception e) { + throw new COPSPepException("Error making Msg"); + } + + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the sync state request, reason: " + e.getMessage()); + } + } + + /** + * Send Delete Request to PDP. + * When sent from the PEP this message indicates to the remote PDP that + * the state identified by the client handle is no longer + * available/relevant. + * + * @throws COPSPepException + * + */ + public void sendDeleteRequest() + throws COPSPepException { + COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_DRQ, _clientType); + COPSHandle handle = _handle; + + // *** TODO: send a real reason + COPSReason reason = new COPSReason((short) 234, (short) 345); + + COPSDeleteMsg msg = new COPSDeleteMsg(); + try { + msg.add(hdr); + msg.add(handle); + msg.add(reason); + } catch (COPSException ex) { + throw new COPSPepException("Error making Msg"); + } + try { + msg.writeData(_sock); + } catch (IOException e) { + throw new COPSPepException("Failed to send the delete request, reason: " + e.getMessage()); + } + } +} + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepReqStateMan.java b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepReqStateMan.java new file mode 100644 index 0000000..c004e82 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/prpep/COPSPepReqStateMan.java @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2004 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.prpep; + +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.umu.cops.stack.COPSContext; +import org.umu.cops.stack.COPSData; +import org.umu.cops.stack.COPSDecision; +import org.umu.cops.stack.COPSDecisionMsg; +import org.umu.cops.stack.COPSError; +import org.umu.cops.stack.COPSHandle; +import org.umu.cops.stack.COPSPrObjBase; +import org.umu.cops.stack.COPSSyncStateMsg; + +/** + * COPSPepReqStateMan manages Request State using Client Handle (RFC 2748 pag. 21) + * in PEP. + * + * The client handle is used to identify a unique request state for a + * single PEP per client-type. Client handles are chosen by the PEP and + * are opaque to the PDP. The PDP simply uses the request handle to + * uniquely identify the request state for a particular Client-Type over + * a particular TCP connection and generically tie its decisions to a + * corresponding request. Client handles are initiated in request + * messages and are then used by subsequent request, decision, and + * report messages to reference the same request state. When the PEP is + * ready to remove a local request state, it will issue a delete message + * to the PDP for the corresponding client handle. A handle MUST be + * explicitly deleted by the PEP before it can be used by the PEP to + * identify a new request state. Handles referring to different request + * states MUST be unique within the context of a particular TCP + * connection and client-type. + * + * @version COPSPepReqStateMan.java, v 2.00 2004 + * + */ +public class COPSPepReqStateMan { + + /** + * Request State created + */ + public final static short ST_CREATE = 1; + /** + * Request sent + */ + public final static short ST_INIT = 2; + /** + * Decisions received + */ + public final static short ST_DECS = 3; + /** + * Report sent + */ + public final static short ST_REPORT = 4; + /** + * Request State finalized + */ + public final static short ST_FINAL = 5; + /** + * New Request State solicited + */ + public final static short ST_NEW = 6; + /** + * Delete Request State solicited + */ + public final static short ST_DEL = 7; + /** + * SYNC Request received + */ + public final static short ST_SYNC = 8; + /** + * SYNC Completed + */ + public final static short ST_SYNCALL = 9; + /** + * Close Connection received + */ + public final static short ST_CCONN = 10; + /** + * KAlive Time out + */ + public final static short ST_NOKA = 11; + /** + * ACCT Time out + */ + public final static short ST_ACCT = 12; + + /** + * The client-type identifies the policy client + */ + protected short _clientType; + + /** + * The client handle is used to uniquely identify a particular + * PEP's request for a client-type + */ + protected COPSHandle _handle; + + /** + The PolicyDataProcess is used to process policy data in the PEP + */ + protected COPSPepDataProcess _process; + + /** + * State Request State + */ + protected short _status; + + /** + The Msg Sender is used to send COPS messages + */ + protected COPSPepMsgSender _sender; + + /** + * Sync State + */ + protected boolean _syncState; + + /** + * Create a State Request Manager + * + * @param clientHandle a Client Handle + * + */ + public COPSPepReqStateMan(short clientType, String clientHandle) { + // COPS Handle + _handle = new COPSHandle(); + COPSData id = new COPSData(clientHandle); + _handle.setId(id); + // client-type + _clientType = clientType; + _syncState = true; + _status = ST_CREATE; + } + + /** + * Return client handle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _handle; + } + + /** + * Return client-type + * + * @return a short + * + */ + public short getClientType() { + return _clientType; + } + + /** + * Return Request State status + * + * @return s short + */ + public short getStatus() { + return _status; + } + + /** + * Return the Policy Data Process + * + * @return a PolicyConfigure + * + */ + public COPSPepDataProcess getDataProcess() { + return _process; + } + + /** + * Establish the Policy Data Process + * + * @param process a PolicyConfigure + * + */ + public void setDataProcess(COPSPepDataProcess process) { + _process = process; + } + + /** + * Init Request State + * + * @throws COPSPepException + * + */ + protected void initRequestState(Socket sock) + throws COPSPepException { + // Inits an object for sending COPS messages to the PDP + _sender = new COPSPepMsgSender(_clientType, _handle, sock); + + // If an object for retrieving PEP features exists, + // use it for retrieving them + Hashtable clientSIs; + if (_process != null) + clientSIs = _process.getClientData(this); + else + clientSIs = null; + + // Send the request + _sender.sendRequest(clientSIs); + + // Initial state + _status = ST_INIT; + } + + /** + * Finalize Request State + * + * @throws COPSPepException + * + */ + protected void finalizeRequestState() + throws COPSPepException { + _sender.sendDeleteRequest(); + _status = ST_FINAL; + } + + /** + * Process the message Decision + * + * @param dMsg a COPSDecisionMsg + * + * @throws COPSPepException + * + */ + protected void processDecision(COPSDecisionMsg dMsg) + throws COPSPepException { + // COPSDebug.out(getClass().getName(), "ClientId:" + getClientHandle().getId().str()); + + // COPSHandle handle = dMsg.getClientHandle(); + Hashtable decisions = dMsg.getDecisions(); + + Hashtable removeDecs = new Hashtable(40); + Hashtable installDecs = new Hashtable(40); + Hashtable errorDecs = new Hashtable(40); + for (Enumeration e = decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) decisions.get(context); + Enumeration ee = v.elements(); + COPSDecision cmddecision = (COPSDecision) ee.nextElement(); + + // cmddecision --> we must check whether it is an error! + + if (cmddecision.isInstallDecision()) { + String prid = new String(); + for (; ee.hasMoreElements() ;) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + + COPSPrObjBase obj = new COPSPrObjBase(decision.getData().getData()); + switch (obj.getSNum()) { + case COPSPrObjBase.PR_PRID: + prid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + installDecs.put(prid, obj.getData().str()); + break; + default: + break; + } + } + } + + if (cmddecision.isRemoveDecision()) { + + String prid = new String(); + for (; ee.hasMoreElements() ;) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + + COPSPrObjBase obj = new COPSPrObjBase(decision.getData().getData()); + switch (obj.getSNum()) { + case COPSPrObjBase.PR_PRID: + prid = obj.getData().str(); + break; + case COPSPrObjBase.PR_EPD: + removeDecs.put(prid, obj.getData().str()); + break; + default: + break; + } + } + } + } + + //** Apply decisions to the configuration + _process.setDecisions(this, removeDecs, installDecs, errorDecs); + _status = ST_DECS; + + + if (_process.isFailReport(this)) { + // COPSDebug.out(getClass().getName(),"Sending FAIL Report\n"); + _sender.sendFailReport(_process.getReportData(this)); + } else { + // COPSDebug.out(getClass().getName(),"Sending SUCCESS Report\n"); + _sender.sendSuccessReport(_process.getReportData(this)); + } + _status = ST_REPORT; + + if (!_syncState) { + _sender.sendSyncComplete(); + _syncState = true; + _status = ST_SYNCALL; + } + } + + /** + * Process the message NewRequestState + * + * @throws COPSPepException + * + */ + protected void processOpenNewRequestState() + throws COPSPepException { + + if (_process != null) + _process.newRequestState(this); + + _status = ST_NEW; + } + + /** + * Process the message DeleteRequestState + * + * @param dMsg a COPSDecisionMsg + * + * @throws COPSPepException + * + */ + protected void processDeleteRequestState(COPSDecisionMsg dMsg) + throws COPSPepException { + if (_process != null) + _process.closeRequestState(this); + + _status = ST_DEL; + } + + /** + * Process the message SycnStateRequest. + * The message SycnStateRequest indicates that the remote PDP + * wishes the client (which appears in the common header) + * to re-send its state. + * + * @param ssMsg a COPSSyncStateMsg + * + * @throws COPSPepException + * + */ + protected void processSyncStateRequest(COPSSyncStateMsg ssMsg) + throws COPSPepException { + _syncState = false; + // If an object for retrieving PEP features exists, + // use it for retrieving them + Hashtable clientSIs; + if (_process != null) + clientSIs = _process.getClientData(this); + else + clientSIs = null; + + // Send request + _sender.sendRequest(clientSIs); + + _status = ST_SYNC; + } + + protected void processClosedConnection(COPSError error) + throws COPSPepException { + if (_process != null) + _process.notifyClosedConnection(this, error); + + _status = ST_CCONN; + } + + protected void processNoKAConnection() + throws COPSPepException { + if (_process != null) + _process.notifyNoKAliveReceived(this); + + _status = ST_NOKA; + } + + protected void processAcctReport() + throws COPSPepException { + + Hashtable report = new Hashtable(); + if (_process != null) + report = _process.getAcctData(this); + + _sender.sendAcctReport(report); + + _status = ST_ACCT; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSAcctTimer.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSAcctTimer.java new file mode 100644 index 0000000..be961c5 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSAcctTimer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Accounting Timer Object + * + * @version COPSAcctTimer.java, v 1.00 2003 + * + */ +public class COPSAcctTimer extends COPSTimer { + + public COPSAcctTimer() { + super ((short) 1); + _objHdr.setCNum(COPSObjHeader.COPS_ACCT_TIMER); + _objHdr.setCType((byte) 1); + } + + /// + public COPSAcctTimer(short timeVal) { + super(timeVal); + _objHdr.setCNum(COPSObjHeader.COPS_ACCT_TIMER); + _objHdr.setCType((byte) 1); + } + + /// + /** + * Method isAcctTimer + * + * @return a boolean + * + */ + public boolean isAcctTimer() { + return true; + } + + /// + protected COPSAcctTimer(byte[] dataPtr) { + super (dataPtr); + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientAcceptMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientAcceptMsg.java new file mode 100644 index 0000000..af72a1a --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientAcceptMsg.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Client Accept Message + * + * @version COPSClientAcceptMsg.java, v 1.00 2003 + * + */ +public class COPSClientAcceptMsg extends COPSMsg { + + /* COPSHeader coming from base class */ + private COPSKATimer _kaTimer; + private COPSAcctTimer _acctTimer; + private COPSIntegrity _integrity; + + ///Constructor + public COPSClientAcceptMsg() { + _kaTimer = null; + _acctTimer = null; + _integrity = null; + } + + ///Create object from data + protected COPSClientAcceptMsg(byte[] data) throws COPSException { + parse(data); + } + + /** Checks the sanity of COPS message and throw an + * COPSBadDataException when data is bad. + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_kaTimer == null)) + throw new COPSException("Bad message format"); + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_CAT) + throw new COPSException ("Error Header (no COPS_OP_CAT)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add Timer object to the message + * + * @param timer a COPSTimer + * + * @throws COPSException + * + */ + public void add (COPSTimer timer) throws COPSException { + if (timer.isKATimer()) { + _kaTimer = (COPSKATimer) timer; + } else { + _acctTimer = (COPSAcctTimer) timer; + } + setMsgLength(); + } + + /** + * Add Integrity objects + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * Method getKATimer + * + * @return a COPSKATimer + * + */ + public COPSKATimer getKATimer() { + return _kaTimer; + }; + + /** + * Returns true if has a account timer object + * + * @return a boolean + * + */ + public boolean hasAcctTimer() { + return (_acctTimer != null); + }; + + /** + * Should check hasAcctTimer() before calling + * + * @return a COPSAcctTimer + * + */ + public COPSAcctTimer getAcctTimer() { + return (_acctTimer); + } + + /** + * Returns true if has a Integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + }; + + /** + * Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return (_integrity); + } + + /** + * Writes data to a given socket id + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null) _hdr.writeData(id); + if (_kaTimer != null) _kaTimer.writeData(id); + if (_acctTimer != null) _acctTimer.writeData(id); + if (_integrity != null) _integrity.writeData(id); + } + + /** + * Method parse + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_KA: { + _kaTimer = new COPSKATimer(buf); + _dataStart += _kaTimer.getDataLength(); + } + break; + case COPSObjHeader.COPS_ACCT_TIMER: { + _acctTimer = new COPSAcctTimer(buf); + _dataStart += _acctTimer.getDataLength(); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format"); + } + } + } + checkSanity(); + } + + /** + * Method parse + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + if (hdr.getOpCode() != COPSHeader.COPS_OP_CAT) + throw new COPSException("Error Header"); + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + short len = 0; + if (_kaTimer != null) len += _kaTimer.getDataLength(); + if (_acctTimer != null) len += _acctTimer.getDataLength(); + if (_integrity != null) len += _integrity.getDataLength(); + _hdr.setMsgLength(len); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_kaTimer != null) + _kaTimer.dump(os); + + if (_acctTimer != null) + _acctTimer.dump(os); + + if (_integrity != null) { + _integrity.dump(os); + } + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientCloseMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientCloseMsg.java new file mode 100644 index 0000000..5fb91e4 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientCloseMsg.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Client Close Message + * + * @version COPSClientCloseMsg.java, v 1.00 2003 + * + */ +public class COPSClientCloseMsg extends COPSMsg { + + /* COPSHeader coming from base class */ + private COPSError _error; + private COPSIntegrity _integrity; + + + public COPSClientCloseMsg() { + _error = null; + _integrity = null; + } + + protected COPSClientCloseMsg(byte[] data) throws COPSException { + parse (data); + } + + /** Checks the sanity of COPS message and throw an + * COPSBadDataException when data is bad. + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_error == null)) + throw new COPSException("Bad message format"); + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_CC) + throw new COPSException ("Error Header (no COPS_OP_CC)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add Error object + * + * @param error a COPSError + * + * @throws COPSException + * + */ + public void add (COPSError error) throws COPSException { + //Message integrity object should be the very last one + //If it is already added + if (_error != null) + throw new COPSException ("No null Error"); + _error = error; + setMsgLength(); + } + + /** + * Add Integrity objects + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * Method getError + * + * @return a COPSError + * + */ + public COPSError getError() { + return (_error); + } + + /** + * Returns true If it has integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + }; + + /** + * Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return (_integrity); + } + + /** + * Write object data to given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null) _hdr.writeData(id); + if (_error != null) _error.writeData(id); + if (_integrity != null) _integrity.writeData(id); + } + + /** + * Method parse + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_ERROR: { + _error = new COPSError(buf); + _dataStart += _error.getDataLength(); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format"); + } + } + } + checkSanity(); + } + + /** + * Method parse + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + if (hdr.getOpCode() != COPSHeader.COPS_OP_CC) + throw new COPSException("Error Header"); + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + int len = 0; + if (_error != null) len += _error.getDataLength(); + if (_integrity != null) len += _integrity.getDataLength(); + _hdr.setMsgLength(len); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_error != null) + _error.dump(os); + + if (_integrity != null) { + _integrity.dump(os); + } + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientOpenMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientOpenMsg.java new file mode 100644 index 0000000..7574757 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientOpenMsg.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Client Open Message + * + * @version COPSClientOpenMsg.java, v 1.00 2003 + * + */ +public class COPSClientOpenMsg extends COPSMsg { + + private COPSPepId _pepId; + private COPSClientSI _clientSI; + private COPSPdpAddress _pdpAddress; + private COPSIntegrity _integrity; + + public COPSClientOpenMsg() { + _pepId = null; + _clientSI = null; + _pdpAddress = null; + _integrity = null; + _hdr = null; + } + + protected COPSClientOpenMsg(byte[] data) throws COPSException { + _pepId = null; + _clientSI = null; + _pdpAddress = null; + _integrity = null; + _hdr = null; + parse(data); + } + + /** + * Method writeData + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null)_hdr.writeData(id); + if (_pepId != null) _pepId.writeData(id); + if (_clientSI != null) _clientSI.writeData(id); + if (_pdpAddress != null) _pdpAddress.writeData(id); + if (_integrity != null) _integrity.writeData(id); + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_OPN) + throw new COPSException ("Error Header (no COPS_OP_OPN)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add PEP Identification Object + * + * @param pepid a COPSPepId + * + * @throws COPSException + * + */ + public void add (COPSPepId pepid) throws COPSException { + if (pepid == null) + throw new COPSException ("Null COPSPepId"); + if (!pepid.isPepId()) + throw new COPSException ("Error COPSPepId"); + _pepId = pepid; + setMsgLength(); + } + + /** + * Add Client Specific Information Object + * + * @param clientSI a COPSClientSI + * + * @throws COPSException + * + */ + public void add (COPSClientSI clientSI) throws COPSException { + if (clientSI == null) + throw new COPSException ("Null COPSClientSI"); + if (!clientSI.isClientSI()) + throw new COPSException ("Error COPSClientSI"); + _clientSI = clientSI; + setMsgLength(); + } + + /** + * Add PDP Address + * + * @param pdpAddr a COPSPdpAddress + * + * @throws COPSException + * + */ + public void add (COPSPdpAddress pdpAddr) throws COPSException { + if (pdpAddr == null) + throw new COPSException ("Null COPSPdpAddress"); + if (!pdpAddr.isLastPdpAddress()) + throw new COPSException ("Error COPSPdpAddress"); + _pdpAddress = pdpAddr; + setMsgLength(); + } + + /** + * Add Integrity object + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** Checks the sanity of COPS message and throw an + * COPSBadDataException when data is bad. + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_pepId == null)) + throw new COPSException("Bad message format"); + } + + /** + * Method getPepId + * + * @return a COPSPepId + * + */ + public COPSPepId getPepId() { + return _pepId; + } + + /** + * Method hasClientSI + * + * @return a boolean + * + */ + public boolean hasClientSI() { + return (_clientSI != null); + } + + /** + * Method getClientSI + * + * @return a COPSClientSI + * + */ + public COPSClientSI getClientSI() { + return (_clientSI); + } + + /** + * Method hasPdpAddress + * + * @return a boolean + * + */ + public boolean hasPdpAddress() { + return (_pdpAddress != null); + } + + /** + * Method getPdpAddress + * + * @return a COPSPdpAddress + * + */ + public COPSPdpAddress getPdpAddress() { + return _pdpAddress; + } + + /** + * Method hasIntegrity + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + } + + /** + * Method getIntegrity + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return _integrity; + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + private void setMsgLength() throws COPSException { + short len = 0; + if (_pepId != null) len += _pepId.getDataLength(); + if (_clientSI != null) len += _clientSI.getDataLength(); + if (_pdpAddress != null) len += _pdpAddress.getDataLength(); + if (_integrity != null) len += _integrity.getDataLength(); + _hdr.setMsgLength(len); + } + + /** + * Method parse + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + parseHeader(data); + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_PEPID: { + _pepId = new COPSPepId(buf); + _dataStart += _pepId.getDataLength(); + } + break; + case COPSObjHeader.COPS_LAST_PDP_ADDR: { + if (objHdr.getCType() == 1) { + _pdpAddress = new COPSIpv4LastPdpAddr(buf); + } else if (objHdr.getCType() == 2) { + _pdpAddress = new COPSIpv6LastPdpAddr(buf); + } + _dataStart += _pdpAddress.getDataLength(); + } + break; + case COPSObjHeader.COPS_CSI: { + _clientSI = new COPSClientSI(buf); + _dataStart += _clientSI.getDataLength(); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format"); + } + } + } + checkSanity(); + } + + /** + * Method parse + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + if (hdr.getOpCode() != COPSHeader.COPS_OP_OPN) + throw new COPSException("Error Header"); + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_pepId != null) + _pepId.dump(os); + + if (_clientSI != null) + _clientSI.dump(os); + + if (_pdpAddress != null) + _pdpAddress.dump(os); + + if (_integrity != null) { + _integrity.dump(os); + } + } +} + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientSI.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientSI.java new file mode 100644 index 0000000..69b5fdd --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSClientSI.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Client Specific Information Object + * + * @version COPSClientSI.java, v 1.00 2003 + * + */ +public class COPSClientSI extends COPSObjBase { + public final static byte CSI_SIGNALED = 1; + public final static byte CSI_NAMED = 2; + + private COPSObjHeader _objHdr; + private COPSData _data; + private COPSData _padding; + + /// + public COPSClientSI(byte type) { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_CSI); + _objHdr.setCType(type); + } + + public COPSClientSI(byte cnum, byte ctype) { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(cnum); + _objHdr.setCType(ctype); + } + + /** + Parse the data and create a ClientSI object + */ + protected COPSClientSI(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + //Get the length of data following the obj header + short dLen = (short) (_objHdr.getDataLength() - 4); + COPSData d = new COPSData(dataPtr, 4, dLen); + setData(d); + } + + /** + * Method setData + * + * @param data a COPSData + * + */ + public void setData(COPSData data) { + _data = data; + if (_data.length() % 4 != 0) { + int padLen = 4 - _data.length() % 4; + _padding = getPadding(padLen); + } + _objHdr.setDataLength((short) _data.length()); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + int lpadding = 0; + if (_padding != null) lpadding = _padding.length(); + return (short) (_objHdr.getDataLength() + lpadding); + } + + /** + * Method getData + * + * @return a COPSData + * + */ + public COPSData getData() { + return _data; + }; + + /** + * Method isClientSI + * + * @return a boolean + * + */ + public boolean isClientSI() { + return true; + } + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + COPSUtil.writeData(id, _data.getData(), _data.length()); + if (_padding != null) { + COPSUtil.writeData(id, _padding.getData(), _padding.length()); + } + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("client-SI: " + _data.str() + "\n").getBytes()); + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSContext.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSContext.java new file mode 100644 index 0000000..5ff6eb3 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSContext.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Context Object + * + * @version COPSContext.java, v 1.00 2003 + * + */ +public class COPSContext extends COPSObjBase { + + public final static byte IN_ADMIN = 0x01; + public final static byte RES_ALLOC = 0x02; + public final static byte OUT = 0x04; + public final static byte CONFIG = 0x08; + + private COPSObjHeader _objHdr; + private short _rType; + private short _mType; + + /// + public COPSContext(short rType, short mType ) { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_CONTEXT); + _objHdr.setCType((byte) 1); + _rType = rType; + _mType = mType; + _objHdr.setDataLength((short) 4); + } + + /** + Parse the data and create a Context object + */ + protected COPSContext(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + _rType |= ((short) dataPtr[4]) << 8; + _rType |= ((short) dataPtr[5]) & 0xFF; + + _mType |= ((short) dataPtr[6]) << 8; + _mType |= ((short) dataPtr[7]) & 0xFF; + + _objHdr.setDataLength( (short) 4); + } + + /** + * Write object in network byte order to a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + + byte[] buf = new byte[4]; + + buf[0] = (byte) (_rType >> 8); + buf[1] = (byte) _rType; + + buf[2] = (byte) (_mType >> 8); + buf[3] = (byte) _mType; + + COPSUtil.writeData(id, buf, 4); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + return (_objHdr.getDataLength()); + } + + /** + * Returns the detail description of the request type + * + * @return a String + * + */ + public String getDescription() { + String retStr = new String(); + if ((_rType & 0x01) != 0) { + retStr += (retStr.length() != 0) ? "," : ""; + retStr += "Incoming Message/Admission Control"; + } + if ((_rType & 0x02) != 0) { + retStr += (retStr.length() != 0) ? "," : ""; + retStr += "Resource allocation"; + } + if ((_rType & 0x04) != 0) { + retStr += (retStr.length() != 0) ? "," : ""; + retStr += "Outgoing message"; + } + if ((_rType & 0x08) != 0) { + retStr += (retStr.length() != 0) ? "," : ""; + retStr += "Configuration"; + } + return retStr; + } + + /** + * Method isIncomingMessage + * + * @return a boolean + * + */ + public boolean isIncomingMessage() { + return (_rType & IN_ADMIN) != 0; + }; + + /** + * Method isAdminControl + * + * @return a boolean + * + */ + public boolean isAdminControl() { + return (_rType & IN_ADMIN) != 0; + }; + + /** + * Method isResourceAllocationReq + * + * @return a boolean + * + */ + public boolean isResourceAllocationReq() { + return (_rType & RES_ALLOC) != 0; + }; + + /** + * Method isOutgoingMessage + * + * @return a boolean + * + */ + public boolean isOutgoingMessage() { + return (_rType & OUT) != 0; + }; + + /** + * Method isConfigRequest + * + * @return a boolean + * + */ + public boolean isConfigRequest() { + return (_rType & CONFIG) != 0; + }; + + /** + * Method getMessageType + * + * @return a short + * + */ + public short getMessageType() { + return (_mType) ; + }; + + /** + * Method getRequestType + * + * @return a short + * + */ + public short getRequestType() { + return (_rType); + }; + + /** + * Method isContext + * + * @return a boolean + * + */ + public boolean isContext() { + return true; + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("context: " + getDescription() + "," + _mType + "\n").getBytes()); + } +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSData.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSData.java new file mode 100644 index 0000000..7b7ab12 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSData.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Data + * + * @version COPSData.java, v 1.00 2003 + * + */ +public class COPSData { + + private byte[] _dataBuf; + private int _dLen; + + public COPSData() { + _dataBuf = null; + _dLen = 0; + } + + public COPSData(byte[] dPtr, int offset, int dLen) { + _dataBuf = new byte[dLen]; + System.arraycopy(dPtr,offset,_dataBuf,0,dLen); + _dLen = dLen; + } + + public COPSData(String data) { + _dLen = data.getBytes().length; + _dataBuf = new byte[_dLen]; + System.arraycopy(data.getBytes(),0,_dataBuf,0,_dLen); + } + + /** + * Method getData + * + * @return a byte[] + * + */ + public byte[] getData() { + return _dataBuf; + } + + /** + * Method length + * + * @return an int + * + */ + public int length() { + return _dLen; + } + + /** + * Method str + * + * @return a String + * + */ + public String str() { + return new String (_dataBuf); + } + + public String toString() { + return str(); + } + + public boolean equals(Object obj) { + return (((COPSData) obj).toString().equals(str())); + } +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDecision.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDecision.java new file mode 100644 index 0000000..095e3f7 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDecision.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Decision + * + * @version COPSDecision.java, v 1.00 2003 + * + */ +public class COPSDecision extends COPSObjBase { + + // CType + public final static byte DEC_DEF = 1; + public final static byte DEC_STATELESS = 2; + public final static byte DEC_REPL = 3; + public final static byte DEC_CSI = 4; + public final static byte DEC_NAMED = 5; + + // Command + public final static byte DEC_NULL = 0; + public final static byte DEC_INSTALL = 1; + public final static byte DEC_REMOVE = 2; + + // Flags + public final static byte F_REQERROR = 0x1; + public final static byte F_REQSTATE = 0x2; + + protected COPSObjHeader _objHdr; + private COPSData _data; + private short _cmdCode; + private short _flags; + private COPSData _padding; + + /** + Constructor to create a Decision object. By default creates + a decision object which is of fixed length. + */ + public COPSDecision(byte cType) { + _objHdr = new COPSObjHeader(); + _cmdCode = 0; + _flags = 0; + _objHdr.setCNum(COPSObjHeader.COPS_DEC); + _objHdr.setCType(cType); + if (cType == DEC_DEF) _objHdr.setDataLength( (short) 4); + } + + public COPSDecision() { + _objHdr = new COPSObjHeader(); + _cmdCode = 0; + _flags = 0; + _objHdr.setCNum(COPSObjHeader.COPS_DEC); + _objHdr.setCType(DEC_DEF); + _objHdr.setDataLength( (short) 4); + } + + /** + Initialize the decision object with values from COPSObj header + */ + protected COPSDecision(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + _cmdCode = 0; + _flags = 0; + if (_objHdr.getCType() == DEC_DEF) { + _cmdCode |= ((short) dataPtr[4]) << 8; + _cmdCode |= ((short) dataPtr[5]) & 0xFF; + _flags |= ((short) dataPtr[6]) << 8; + _flags |= ((short) dataPtr[7]) & 0xFF; + + _objHdr.setDataLength((short) 4); + } else { + int dLen = _objHdr.getDataLength() - 4; + COPSData d = new COPSData(dataPtr, 4, dLen); + setData(d); + } + } + + /** + * Method getDataLength + * + * @return a short + * + */ + public short getDataLength() { + int lpadding = 0; + if (_padding != null) lpadding = _padding.length(); + return ((short) (_objHdr.getDataLength() + lpadding)); + } + + + + /** + * Get the associated data if decision object is of cType 2 or higher + * + * @return a COPSData + * + */ + public COPSData getData() { + return (_data); + } + + /** + * Set the decision data if decision object is of cType 2 or higher + * + * @param data a COPSData + * + */ + public void setData(COPSData data) { + if (data.length() % 4 != 0) { + int padLen = 4 - data.length() % 4; + _padding = getPadding(padLen); + } + _data = data; + _objHdr.setDataLength((short) data.length()); + } + + /** + * Retruns true if cType = 1 + * + * @return a boolean + * + */ + public boolean isFlagSet() { + return ( _objHdr.getCType() == 1); + }; + + /** + * If cType == 1 , get the flags associated + * + * @return a short + * + */ + public short getFlags() { + return (_flags); + }; + + /** + * If cType == 1 ,set the cmd code + * + * @param cCode a byte + * + */ + public void setCmdCode(byte cCode) { + _cmdCode = (short) cCode; + } + + /** + * If cType == 1 ,set the cmd flags + * + * @param flags a short + * + */ + public void setFlags(short flags) { + _flags = flags; + } + + /** + * Method isNullDecision + * + * @return a boolean + * + */ + public boolean isNullDecision() { + return ( _cmdCode == 0); + }; + + /** + * Method isInstallDecision + * + * @return a boolean + * + */ + public boolean isInstallDecision() { + return ( _cmdCode == 1); + }; + + /** + * Method isRemoveDecision + * + * @return a boolean + * + */ + public boolean isRemoveDecision() { + return ( _cmdCode == 2); + }; + + /** + * Method getTypeStr + * + * @return a String + * + */ + public String getTypeStr() { + switch (_objHdr.getCType()) { + case DEC_DEF: + return "Default"; + case DEC_STATELESS: + return "Stateless data"; + case DEC_REPL: + return "Replacement data"; + case DEC_CSI: + return "Client specific decision data"; + case DEC_NAMED: + return "Named decision data"; + default: + return "Unknown"; + } + } + + /** + * Method isDecision + * + * @return a boolean + * + */ + public boolean isDecision() { + return true; + }; + + /** + * Method isLocalDecision + * + * @return a boolean + * + */ + public boolean isLocalDecision() { + return false; + }; + + /** + * Writes data to a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + + if (_objHdr.getCType() >= 2) { + COPSUtil.writeData(id, _data.getData(), _data.length()); + if (_padding != null) { + COPSUtil.writeData(id, _padding.getData(), _padding.length()); + } + } else { + byte[] buf = new byte[4]; + buf[0] = (byte) (_cmdCode >> 8); + buf[1] = (byte) _cmdCode; + buf[2] = (byte) (_flags >> 8); + buf[3] = (byte) _flags; + COPSUtil.writeData(id, buf, 4); + } + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + + if (_objHdr.getCType() == 1) { + os.write(new String("Decision (" + getTypeStr() + ")\n").getBytes()); + os.write(new String("Command code: " + _cmdCode + "\n").getBytes()); + os.write(new String("Command flags: " + _flags + "\n").getBytes()); + } else { + os.write(new String("Decision (" + getTypeStr() + ")\n").getBytes()); + os.write(new String("Data: " + _data.str() + "\n").getBytes()); + } + } +} + + + + + + + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDecisionMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDecisionMsg.java new file mode 100644 index 0000000..3539d23 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDecisionMsg.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +/** + * COPS Decision Message + * + * @version COPSDecisionMsg.java, v 1.00 2003 + * + */ +public class COPSDecisionMsg extends COPSMsg { + + /* COPSHeader coming from base class */ + private COPSHandle _clientHandle; + private COPSError _error; + private Hashtable _decisions; + private COPSIntegrity _integrity; + private COPSContext _decContext; + private COPSClientSI _decSI; + + /// + public COPSDecisionMsg() { + _clientHandle = null; + _error = null; + _decisions = new Hashtable(20); + _integrity = null; + _decContext = null; + _decSI = null; + } + + /** Checks the sanity of COPS message and throw an + * COPSBadDataException when data is bad. + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_clientHandle == null) || ( (_error == null) && (_decisions.size() == 0))) { + throw new COPSException("Bad message format"); + } + } + + /// + protected COPSDecisionMsg(byte[] data) throws COPSException { + _decisions = new Hashtable(20); + _clientHandle = null; + _error = null; + _integrity = null; + _decContext = null; + _decSI = null; + + parse(data); + } + + /** + * Parses the data and fills COPSDecisionMsg with its constituents + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + super.parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_HANDLE: { + _clientHandle = new COPSHandle(buf); + _dataStart += _clientHandle.getDataLength(); + } + break; + case COPSObjHeader.COPS_CONTEXT: { + //dec context + _decContext = new COPSContext(buf); + _dataStart += _decContext.getDataLength(); + } + break; + case COPSObjHeader.COPS_ERROR: { + _error = new COPSError(buf); + _dataStart += _error.getDataLength(); + } + break; + case COPSObjHeader.COPS_DEC: { + COPSDecision decs = new COPSDecision(buf); + _dataStart += decs.getDataLength(); + addDecision(decs, _decContext); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format, unknown object type"); + } + } + } + checkSanity(); + } + + /** + * Parses the data and fills that follows the header hdr and fills COPSDecisionMsg + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_DEC) + throw new COPSException ("Error Header (no COPS_OP_DEC)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add client handle to the message + * + * @param handle a COPSHandle + * + * @throws COPSException + * + */ + public void add (COPSHandle handle) throws COPSException { + if (handle == null) + throw new COPSException ("Null Handle"); + _clientHandle = handle; + setMsgLength(); + } + + /** + * Add an Error object + * + * @param error a COPSError + * + * @throws COPSException + * + */ + public void add (COPSError error) throws COPSException { + if (_decisions.size() != 0) + throw new COPSException ("No null decisions"); + if (_error != null) + throw new COPSException ("No null error"); + //Message integrity object should be the very last one + //If it is already added + if (_integrity != null) + throw new COPSException ("No null integrity"); + _error = error; + setMsgLength(); + } + + /** + * Add one or more local decision object for a given decision context + * the context is optional, if null all decision object are tided to + * message context + * + * @param decision a COPSDecision + * @param context a COPSContext + * + * @throws COPSException + * + */ + public void addDecision(COPSDecision decision, COPSContext context) throws COPSException { + //Either error or decision can be added + //If error is aleady there assert + if (_error != null) + throw new COPSException ("No null error"); + + if (decision.isLocalDecision()) + throw new COPSException ("Is local decision"); + + Vector v = (Vector) _decisions.get(context); + if (v == null) v = new Vector(); + + if (decision.isFlagSet()) {//Commented out as advised by Felix + //if (v.size() != 0) + //{ + //Only one set of decision flags is allowed + //for each context + // throw new COPSException ("Bad Message format, only one set of decision flags is allowed."); + //} + } else { + if (v.size() == 0) { + //The flags decision must precede any other + //decision message, since the decision is not + //flags throw exception + throw new COPSException ("Bad Message format, flags decision must precede any other decision object."); + } + } + v.add(decision); + _decisions.put(context,v); + + setMsgLength(); + } + + /** + * Add integrity object + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + /** + * Add clientSI object + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSClientSI clientSI) throws COPSException { + if (clientSI == null) + throw new COPSException ("Null clientSI"); + /* + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + */ + _decSI = clientSI; + setMsgLength(); + } + + /** + * Writes data to given socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null) _hdr.writeData(id); + if (_clientHandle != null) _clientHandle.writeData(id); + if (_error != null) _error.writeData(id); + + //Display decisions + //Display any local decisions + for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + context.writeData(id); + + for (Enumeration ee = v.elements() ; ee.hasMoreElements() ;) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + decision.writeData(id); + } + } + + if (_decSI != null) _decSI.writeData(id); + if (_integrity != null) _integrity.writeData(id); + } + + /** + * Method getHeader + * + * @return a COPSHeader + * + */ + public COPSHeader getHeader() { + return _hdr; + } + + /** + * Method getClientHandle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _clientHandle; + } + + /** + * Returns true if it has error object + * + * @return a boolean + * + */ + public boolean hasError() { + return (_error != null); + }; + + /** + * Should check hasError() before calling + * + * @return a COPSError + * + */ + public COPSError getError() { + return _error; + }; + + /** + * Returns a map of decision for which is an arry of context and vector + * of associated decision object. + * + * @return a Hashtable + * + */ + public Hashtable getDecisions() { + return _decisions; + }; + + /** + * Returns true if it has integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + }; + + /** + * Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return _integrity; + }; + + /** + * Method setMsgLength + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + short len = 0; + if (_clientHandle != null) + len += _clientHandle.getDataLength(); + if (_error != null) + len += _error.getDataLength(); + + //Display any local decisions + for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + len += context.getDataLength(); + + for (Enumeration ee = v.elements() ; ee.hasMoreElements() ;) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + len += decision.getDataLength(); + } + } + if (_decSI != null) { + len += _decSI.getDataLength(); + } + if (_integrity != null) { + len += _integrity.getDataLength(); + } + + _hdr.setMsgLength((int) len); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_clientHandle != null) + _clientHandle.dump(os); + if (_error != null) + _error.dump(os); + + //Display any local decisions + for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + context.dump(os); + + for (Enumeration ee = v.elements() ; ee.hasMoreElements() ;) { + COPSDecision decision = (COPSDecision) ee.nextElement(); + decision.dump(os); + } + } + if (_decSI != null) { + _decSI.dump(os); + } + if (_integrity != null) { + _integrity.dump(os); + } + } +} + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDeleteMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDeleteMsg.java new file mode 100644 index 0000000..9499713 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSDeleteMsg.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Delete Message (RFC 2748 pag. 24) + * + * When sent from the PEP this message indicates to the remote PDP that + * the state identified by the client handle is no longer + * available/relevant. This information will then be used by the remote + * PDP to initiate the appropriate housekeeping actions. The reason code + * object is interpreted with respect to the client-type and signifies + * the reason for the removal. + * + * The format of the Delete Request State message is as follows: + * + * ::= + * + * + * [] + * + * + * @version COPSDeleteMsg.java, v 1.00 2003 + * + */ +public class COPSDeleteMsg extends COPSMsg { + /* COPSHeader coming from base class */ + private COPSHandle _clientHandle; + private COPSReason _reason; + private COPSIntegrity _integrity; + + public COPSDeleteMsg() { + _clientHandle = null; + _reason = null; + _integrity = null; + } + + /** + Parse data and create COPSDeleteMsg object + */ + protected COPSDeleteMsg(byte[] data) throws COPSException { + _clientHandle = null; + _reason = null; + _integrity = null; + parse(data); + } + + /** + * Checks the sanity of COPS message and throw an + * COPSException when data is bad. + * + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_clientHandle == null) || (_reason == null)) + throw new COPSException("Bad message format"); + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_DRQ) + throw new COPSException ("Error Header (no COPS_OP_DRQ)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add Reason object to the message + * + * @param reason a COPSReason + * + * @throws COPSException + * + */ + public void add (COPSReason reason) throws COPSException { + if (_reason != null) + throw new COPSException ("No null Reason"); + + //Message integrity object should be the very last one + //If it is already added + if (_integrity != null) + throw new COPSException ("No null Integrity"); + _reason = reason; + setMsgLength(); + } + + /** + * Add Handle object + * + * @param handle a COPSHandle + * + * @throws COPSException + * + */ + public void add (COPSHandle handle) throws COPSException { + if (handle == null) + throw new COPSException ("Null Handle"); + _clientHandle = handle; + setMsgLength(); + } + + /** + * Add Integrity object + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * Get Client Handle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _clientHandle; + }; + + /** + * Get Reason + * + * @return a COPSReason + * + */ + public COPSReason getReason() { + return _reason; + }; + + /** + * Returns true if it has integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + }; + + /** + * Get Integrity. Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return (_integrity); + } + + /** + * Writes data to given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + if (_hdr != null) _hdr.writeData(id); + if (_clientHandle != null) _clientHandle.writeData(id); + if (_reason != null) _reason.writeData(id); + if (_integrity != null) _integrity.writeData(id); + } + + /** + * Parse data + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + super.parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_HANDLE: { + _clientHandle = new COPSHandle(buf); + _dataStart += _clientHandle.getDataLength(); + } + break; + case COPSObjHeader.COPS_REASON_CODE: { + _reason = new COPSReason(buf); + _dataStart += _reason.getDataLength(); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format, unknown object type"); + } + } + } + checkSanity(); + } + + /** + * Parse data + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + if (hdr.getOpCode() != COPSHeader.COPS_OP_DRQ) + throw new COPSException("Error Header"); + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + short len = 0; + if (_clientHandle != null) len += _clientHandle.getDataLength(); + if (_reason != null) len += _reason.getDataLength(); + if (_integrity != null) len += _integrity.getDataLength(); + _hdr.setMsgLength(len); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_clientHandle != null) + _clientHandle.dump(os); + + if (_reason != null) + _reason.dump(os); + + if (_integrity != null) { + _integrity.dump(os); + } + } + +} + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSError.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSError.java new file mode 100644 index 0000000..3bd184b --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSError.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Error + * + * @version COPSError.java, v 1.00 2003 + * + */ +public class COPSError extends COPSObjBase { + + public final static byte COPS_ERR_BAD_HANDLE = 1; + public final static byte COPS_ERR_BAD_HANDLE_REF = 2; + public final static byte COPS_ERR_BAD_MSG_FORMAT = 3; + public final static byte COPS_ERR_FAIL_PROCESS = 4; + public final static byte COPS_ERR_MISSING_INFO = 5; + public final static byte COPS_ERR_UNSUPPORTED_CLIENT_TYPE = 6; + public final static byte COPS_ERR_MANDATORY_OBJECT_MISSING = 7; + public final static byte COPS_ERR_CLIENT_FAILURE = 8; + public final static byte COPS_ERR_COMM_FAILURE = 9; + public final static byte COPS_ERR_UNKNOWN = 10; + public final static byte COPS_ERR_SHUTTING_DOWN = 11; + public final static byte COPS_ERR_PDP_REDIRECT = 12; + public final static byte COPS_ERR_UNKNOWN_OBJECT = 13; + public final static byte COPS_ERR_AUTH_FAILURE = 14; + public final static byte COPS_ERR_AUTH_REQUIRED = 15; + public final static byte COPS_ERR_MA = 16; + + private final static String G_errmsgArray[] = { + "Unknown.", + "Bad handle.", + "Invalid handle reference.", + "Bad message format (Malformed message).", + "Unable to process.", + "Mandatory client-specific info missing.", + "Unsupported client-type", + "Mandatory COPS object missing.", + "Client failure.", + "Communication failure.", + "Unknown.", + "Shutting down.", + "Redirect to preferred server.", + "Unknown COPS object", + "Authentication failure.", + "Authentication required.", + }; + + private COPSObjHeader _objHdr; + private short _errCode; + private short _errSubCode; + + public COPSError(short errCode, short subCode) { + _objHdr = new COPSObjHeader(); + _errCode = errCode; + _errSubCode = subCode; + _objHdr.setCNum(COPSObjHeader.COPS_ERROR); + _objHdr.setCType((byte) 1); + _objHdr.setDataLength((short) 4); + } + + protected COPSError(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + _errCode |= ((short) dataPtr[4]) << 8; + _errCode |= ((short) dataPtr[5]) & 0xFF; + _errSubCode |= ((short) dataPtr[6]) << 8; + _errSubCode |= ((short) dataPtr[7]) & 0xFF; + + // _objHdr.setDataLength(sizeof(u_int32_t)); + _objHdr.setDataLength((short) 4); + } + + public short getErrCode() { + return _errCode; + } + + public short getErrSubCode() { + return _errSubCode; + } + /** + * Returns size in number of octects + * + * @return a short + * + */ + public short getDataLength() { + return (_objHdr.getDataLength()); + }; + + /** + * Method getDescription + * + * @return a String + * + */ + public String getDescription() { + String errStr1; + String errStr2; + + ///Get the details from the error code + errStr1 = G_errmsgArray[_errCode]; + //TODO - define error sub-codes + errStr2 = ""; + return (errStr1 + ":" + errStr2); + } + + /** + * Method isError + * + * @return a boolean + * + */ + public boolean isError() { + return true; + }; + + /** + * Writes object to given network socket in network byte order + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + + byte[] buf = new byte[4]; + + buf[0] = (byte) (_errCode >> 8); + buf[1] = (byte) _errCode; + buf[2] = (byte) (_errSubCode >> 8); + buf[3] = (byte) _errSubCode; + + COPSUtil.writeData(id, buf, 4); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("Error Code: " + _errCode + "\n").getBytes()); + os.write(new String("Error Sub Code: " + _errSubCode + "\n").getBytes()); + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSException.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSException.java new file mode 100644 index 0000000..127ce61 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +/** + * COPS Exception + * + * @version COPSException.java, v 1.00 2003 + * + */ +public class COPSException extends Exception { + + private int rc; + final static int GENERAL_ERROR = 0x00000001; + + public COPSException(String s) { + super(s); + rc=0; + } + + public COPSException(String msg, int retCode) { + super(msg); + rc = retCode; + } + + /** + * Method returnCode + * + * @return an int + * + */ + public int returnCode() { + return rc; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSHandle.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSHandle.java new file mode 100644 index 0000000..dc652e3 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSHandle.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Handle Object (RFC 2748 pag. 9) + * + * The Handle Object encapsulates a unique value that identifies an + * installed state. This identification is used by most COPS operations. + * + * C-Num = 1 + * + * C-Type = 1, Client Handle. + * + * Variable-length field, no implied format other than it is unique from + * other client handles from the same PEP (a.k.a. COPS TCP connection) + * for a particular client-type. It is always initially chosen by the + * PEP and then deleted by the PEP when no longer applicable. The client + * handle is used to refer to a request state initiated by a particular + * PEP and installed at the PDP for a client-type. A PEP will specify a + * client handle in its Request messages, Report messages and Delete + * messages sent to the PDP. In all cases, the client handle is used to + * uniquely identify a particular PEP's request for a client-type. + * + * The client handle value is set by the PEP and is opaque to the PDP. + * The PDP simply performs a byte-wise comparison on the value in this + * object with respect to the handle object values of other currently + * installed requests. + * + * @version COPSHandle.java, v 1.00 2003 + * + */ +public class COPSHandle extends COPSObjBase { + + private COPSObjHeader _objHdr; + private COPSData _id; + private COPSData _padding; + + public COPSHandle() { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_HANDLE); + _objHdr.setCType((byte) 1); + _padding = new COPSData(); + } + + /** + Parse data and create COPSHandle object + */ + protected COPSHandle(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + //Get the length of data following the obj header + int dLen = _objHdr.getDataLength() - 4; + COPSData d = new COPSData (dataPtr, 4, dLen); + setId(d); + } + + /** + * Set handle value + * + * @param id a COPSData + * + */ + public void setId(COPSData id) { + _id = id; + if ((id.length() % 4) != 0) { + int padLen = 4 - (_id.length() % 4); + _padding = getPadding(padLen); + } + _objHdr.setDataLength((short) _id.length()); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + int lpadding = 0; + if (_padding != null) lpadding = _padding.length(); + return ((short) (_objHdr.getDataLength() + lpadding)); + } + + /** + * Get handle value + * + * @return a COPSData + * + */ + public COPSData getId() { + return _id; + } + + /** + * Always return true + * + * @return a boolean + * + */ + public boolean isClientHandle() { + return true; + } + + /** + * Write data in network byte order on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + + COPSUtil.writeData(id, _id.getData(), _id.length()); + if (_padding != null) { + COPSUtil.writeData(id, _padding.getData(), _padding.length()); + } + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("client-handle: " + _id.str() + "\n").getBytes()); + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSHeader.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSHeader.java new file mode 100644 index 0000000..90a0a63 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSHeader.java @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Header (RFC 2748 pag. 6) + * + * Each COPS message consists of the COPS header followed by a number of + * typed objects. + * + * 0 1 2 3 + * +--------------+--------------+--------------+--------------+ + * |Version| Flags| Op Code | Client-type | + * +--------------+--------------+--------------+--------------+ + * | Message Length | + * +--------------+--------------+--------------+--------------+ + * + * Global note: //// implies field is reserved, set to 0. + * + * The fields in the header are: + * Version: 4 bits + * COPS version number. Current version is 1. + * + * Flags: 4 bits + * Defined flag values (all other flags MUST be set to 0): + * 0x1 Solicited Message Flag Bit + * This flag is set when the message is solicited by + * another COPS message. This flag is NOT to be set + * (value=0) unless otherwise specified. + * + * Op Code: 8 bits + * The COPS operations: + * 1 = Request (REQ) + * 2 = Decision (DEC) + * 3 = Report State (RPT) + * 4 = Delete Request State (DRQ) + * 5 = Synchronize State Req (SSQ) + * 6 = Client-Open (OPN) + * 7 = Client-Accept (CAT) + * 8 = Client-Close (CC) + * 9 = Keep-Alive (KA) + * 10= Synchronize Complete (SSC) + * + * Client-type: 16 bits + * + * + * @version COPSHeader.java, v 1.00 2003 + * + */ +public class COPSHeader { + + public final static byte COPS_OP_REQ = 1; + public final static byte COPS_OP_DEC = 2; + public final static byte COPS_OP_RPT = 3; + public final static byte COPS_OP_DRQ = 4; + public final static byte COPS_OP_SSQ = 5; + public final static byte COPS_OP_OPN = 6; + public final static byte COPS_OP_CAT = 7; + public final static byte COPS_OP_CC = 8; + public final static byte COPS_OP_KA = 9; + public final static byte COPS_OP_SSC = 10; + + public final static byte COPS_FLAG_NULL = 0; + public final static byte COPS_FLAG_SOLICITED = 1; + + private byte _versionNflg; + private byte _opCode; + private short _cType; + private int _msgLength; + + public COPSHeader() { + _versionNflg = 0x10; + _opCode = 0; + _cType = 0; + _msgLength = 0; + } + + public COPSHeader(byte opCode, short clientType) { + _versionNflg = 0x10; + _opCode = opCode; + _cType = clientType; + _msgLength = 0; + if (isAKeepAlive()) _cType = 0; + } + + public COPSHeader(byte opCode) { + _versionNflg = 0x10; + _opCode = opCode; + _cType = 0; + _msgLength = 0; + if (isAKeepAlive()) _cType = 0; + } + + /** + Parse data and create COPSHeader object + */ + public COPSHeader(byte[] buf) { + _versionNflg = (byte) buf[0]; + _opCode = (byte) buf[1]; + _cType |= ((short) buf[2]) << 8; + _cType |= ((short) buf[3]) & 0xFF; + _msgLength |= ((short) buf[4]) << 24; + _msgLength |= ((short) buf[5]) << 16; + _msgLength |= ((short) buf[6]) << 8; + _msgLength |= ((short) buf[7]) & 0xFF; + } + + /** + * If the operation code corresponds with a message Request, return true + * + * @return a boolean + * + */ + public boolean isARequest() { + return (_opCode == COPS_OP_REQ); + } + + /** + * If the operation code corresponds with a message Decision, return true + * + * @return a boolean + * + */ + public boolean isADecision() { + return (_opCode == COPS_OP_DEC); + } + + /** + * If the operation code corresponds with a message Report, return true + * + * @return a boolean + * + */ + public boolean isAReport() { + return (_opCode == COPS_OP_RPT); + } + + /** + * If the operation code corresponds with a message DeleteRequest, return true + * + * @return a boolean + * + */ + public boolean isADeleteReq() { + return (_opCode == COPS_OP_DRQ); + } + + /** + * If the operation code corresponds with a message SyncStateReq, return true + * + * @return a boolean + * + */ + public boolean isASyncStateReq() { + return (_opCode == COPS_OP_SSQ); + } + + /** + * If the operation code corresponds with a message ClientOpen, return true + * + * @return a boolean + * + */ + public boolean isAClientOpen() { + return (_opCode == COPS_OP_OPN); + } + + /** + * If the operation code corresponds with a message ClientAccept, return true + * + * @return a boolean + * + */ + public boolean isAClientAccept() { + return (_opCode == COPS_OP_CAT); + } + + /** + * If operation code corresponds with a message ClientClose, return true + * + * @return a boolean + * + */ + public boolean isAClientClose() { + return (_opCode == COPS_OP_CC); + } + + /** + * If the operation code corresponds with a message KeepAlive, return true + * + * @return a boolean + * + */ + public boolean isAKeepAlive() { + return (_opCode == COPS_OP_KA); + } + + /** + * If the operation code corresponds with a message SSC, return true + * + * @return a boolean + * + */ + public boolean isASyncComplete() { + return (_opCode == COPS_OP_SSC); + } + + /** + * Get message length + * + * @return an int + * + */ + public int getMsgLength() { + return _msgLength; + } + + /** + * Get header length + * + * @return an int + * + */ + public int getHdrLength() { + // return (sizeof(u_int32_t) * 2); + return ( 8 ); + } + + /** + * Get Operation Code + * + * @return a byte + * + */ + public byte getOpCode() { + return _opCode; + } + + /** + * Set the solicitation flag + * + * @param flg a byte + * + */ + public void setFlag(byte flg) { + _versionNflg &= 0x10; + _versionNflg |= flg; + } + + /** + * Returns the flags field + * @return aByte Flags field in header + */ + public byte getFlags() { //OJO + return (byte) (_versionNflg & 0x0f); + } + + /** + * Set the client-type + * + * @param cType a short + * + */ + public void setClientType(short cType) { + _cType = cType; + }; + + /** + * Set the message length + * + * @param len an int + * + * @throws COPSException + * + */ + public void setMsgLength(int len) throws COPSException { + if ((len % 4) != 0) + throw new COPSException ("Message is not aligned on 32 bit intervals"); + _msgLength = len + 8; + } + + /** + * Get client-type + * + * @return a short + * + */ + public short getClientType() { + return (_cType); + }; + + /** + * Always return true + * + * @return a boolean + * + */ + public boolean isCOPSHeader() { + return true; + }; + + /** + * Writes object to given network socket in network byte order + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + byte buf[] = new byte[8]; + + buf[0] = (byte) _versionNflg; + buf[1] = (byte) _opCode; + buf[2] = (byte) (_cType >> 8); + buf[3] = (byte) _cType; + buf[4] = (byte) (_msgLength >> 24); + buf[5] = (byte) (_msgLength >> 16); + buf[6] = (byte) (_msgLength >> 8); + buf[7] = (byte) _msgLength; + + COPSUtil.writeData(id, buf, 8); + } + + /** + * Get an object textual description + * + * @return a String + * + */ + public String toString() { + String str = new String(); + + str += "**MSG HEADER** \n"; + str += "Version: " + (_versionNflg >> 4) + "\n"; + str += "Flags: " + (_versionNflg & 0x01) + "\n"; + str += "OpCode: " + _opCode + "\n"; + str += "Client-type: " + _cType + "\n"; + str += "Message-length(bytes): " + _msgLength + "\n"; + return str; + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + os.write(new String("**MSG HEADER**" + "\n").getBytes()); + os.write(new String("Version: " + (_versionNflg >> 4) + "\n").getBytes()); + os.write(new String("Flags: " + (_versionNflg & 0x01) + "\n").getBytes()); + os.write(new String("OpCode: " + _opCode + "\n").getBytes()); + os.write(new String("Client-type: " + _cType + "\n").getBytes()); + os.write(new String("Message-length(bytes): " + _msgLength + "\n").getBytes()); + } +} + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIntegrity.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIntegrity.java new file mode 100644 index 0000000..84ff09b --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIntegrity.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Integrity Object + * + * @version COPSIntegrity.java, v 1.00 2003 + * + */ +public class COPSIntegrity extends COPSObjBase { + private COPSObjHeader _objHdr; + private int _keyId; + private int _seqNum; + private COPSData _keyDigest; + private COPSData _padding; + + public COPSIntegrity() { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_MSG_INTEGRITY); + _objHdr.setCType((byte) 1); + _keyId = 0; + _seqNum = 0; + } + + public COPSIntegrity(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + _keyId |= ((short) dataPtr[4]) << 24; + _keyId |= ((short) dataPtr[5]) << 16; + _keyId |= ((short) dataPtr[6]) << 8; + _keyId |= ((short) dataPtr[7]) & 0xFF; + _seqNum |= ((short) dataPtr[8]) << 24; + _seqNum |= ((short) dataPtr[9]) << 16; + _seqNum |= ((short) dataPtr[10]) << 8; + _seqNum |= ((short) dataPtr[11]) & 0xFF; + + int dLen = _objHdr.getDataLength() - 12; + COPSData d = new COPSData(dataPtr, 12, dLen); + setKeyDigest(d); + } + + /** + * Method setKeyId + * + * @param keyId an int + * + */ + public void setKeyId(int keyId) { + _keyId = keyId; + }; + + /** + * Method setSeqNum + * + * @param seqNum an int + * + */ + public void setSeqNum(int seqNum) { + _seqNum = seqNum; + }; + + /** + * Method setKeyDigest + * + * @param keyDigest a COPSData + * + */ + public void setKeyDigest(COPSData keyDigest) { + _keyDigest = keyDigest; + if (_keyDigest.length() % 4 != 0) { + int padLen = 4 - _keyDigest.length() % 4; + _padding = getPadding(padLen); + } + // _objHdr.setDataLength(sizeof(u_int32_t) + // + sizeof(u_int32_t) + _keyDigest.length()); + _objHdr.setDataLength((short) (8 + _keyDigest.length())); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + int lpadding = 0; + if (_padding != null) lpadding = _padding.length(); + return ((short) (_objHdr.getDataLength() + lpadding)); + } + + /** + * Method getKeyId + * + * @return an int + * + */ + public int getKeyId() { + return _keyId; + }; + + /** + * Method getSeqNum + * + * @return an int + * + */ + public int getSeqNum() { + return _seqNum; + }; + + /** + * Method getKeyDigest + * + * @return a COPSData + * + */ + public COPSData getKeyDigest() { + return _keyDigest; + }; + + /** + * Method isMessageIntegrity + * + * @return a boolean + * + */ + public boolean isMessageIntegrity() { + return true; + }; + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + + byte[] buf = new byte[8]; + buf[0] = (byte) (_keyId >> 24); + buf[1] = (byte) (_keyId >> 16); + buf[2] = (byte) (_keyId >> 8); + buf[3] = (byte) _keyId; + buf[4] = (byte) (_seqNum >> 24); + buf[5] = (byte) (_seqNum >> 16); + buf[6] = (byte) (_seqNum >> 8); + buf[7] = (byte) _seqNum; + COPSUtil.writeData(id, buf, 8); + + COPSUtil.writeData(id, _keyDigest.getData(), _keyDigest.length()); + if (_padding != null) { + COPSUtil.writeData(id, _padding.getData(), _padding.length()); + } + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("Key Id: " + _keyId + "\n").getBytes()); + os.write(new String("Sequence: " + _seqNum + "\n").getBytes()); + os.write(new String("Key digest: " + _keyDigest.str() + "\n").getBytes()); + } +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSInterface.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSInterface.java new file mode 100644 index 0000000..7d6b746 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSInterface.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Interface + * + * @version COPSInterface.java, v 1.00 2003 + * + */ +abstract class COPSInterface extends COPSObjBase { + /** + * Method isIpv4Address + * + * @return a boolean + * + */ + protected boolean isIpv4Address() { + return false; + }; + + /** + * Method isIpv6Address + * + * @return a boolean + * + */ + protected boolean isIpv6Address() { + return false; + }; + + /** + * Method isInInterface + * + * @return a boolean + * + */ + protected boolean isInInterface() { + return false; + }; + + /** + * Method isOutInterface + * + * @return a boolean + * + */ + protected boolean isOutInterface() { + return false; + }; + + /** + * Method isInterface + * + * @return a boolean + * + */ + protected boolean isInterface() { + return true; + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4Address.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4Address.java new file mode 100644 index 0000000..2bb7d87 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4Address.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * COPS IPv4 Address + * + * @version COPSIpv4Address.java, v 1.00 2003 + * + */ +public class COPSIpv4Address { + + private byte[] _addr; + + public COPSIpv4Address() { + _addr = new byte[4]; + } + + public COPSIpv4Address(String hostName) throws UnknownHostException { + setIpAddress(hostName); + } + + /** + * Method setIpAddress + * + * @param hostName a String + * + * @throws UnknownHostException + * + */ + public void setIpAddress(String hostName) throws UnknownHostException { + _addr = InetAddress.getByName(hostName).getAddress(); + } + + /** + * Method getIpName + * + * @return a String + * + * @throws UnknownHostException + * + */ + public String getIpName() throws UnknownHostException { + return InetAddress.getByAddress(_addr).getHostName(); + } + + /** + * Method getIpAddress + * + * @return an int + * + */ + public int getIpAddress() { + int ipaddr = 0; + + ipaddr |= ((int) _addr[0]) << 24; + ipaddr |= ((int) _addr[1]) << 16; + ipaddr |= ((int) _addr[2]) << 8; + ipaddr |= ((int) _addr[3]) & 0xFF; + + return ipaddr; + } + + /** + * Method parse + * + * @param dataPtr a byte[] + * + */ + public void parse(byte[] dataPtr) { + new ByteArrayInputStream(dataPtr).read(_addr,0,4); + } + + /** + * Method getDataLength + * + * @return a short + * + */ + public short getDataLength() { + return (4); + } + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + COPSUtil.writeData(id, _addr, 4); + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4InInterface.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4InInterface.java new file mode 100644 index 0000000..d3a2c02 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4InInterface.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; + +/** + * COPS IPv4 Input Address + * + * @version COPSIpv4InInterface.java, v 1.00 2003 + * + */ +public class COPSIpv4InInterface extends COPSIpv4Interface { + public COPSIpv4InInterface() { + _objHdr.setCNum(COPSObjHeader.COPS_ININTF); + } + + public COPSIpv4InInterface(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method className + * + * @return a String + * + */ + public String className() { + return "COPSIpv4InInterface"; + } + + /** + * Method isInInterface + * + * @return a boolean + * + */ + public boolean isInInterface() { + return true; + } + + /** + * Writes data to given socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4Interface.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4Interface.java new file mode 100644 index 0000000..d22d788 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4Interface.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.net.UnknownHostException; + +/** + * COPS IPv4 Interface + * + * @version COPSIpv4Interface.java, v 1.00 2003 + * + */ +public abstract class COPSIpv4Interface extends COPSInterface { + + protected COPSObjHeader _objHdr; + private COPSIpv4Address _addr; + private int _ifindex; + + + /** + * Method isIpv4Address + * + * @return a boolean + * + */ + public boolean isIpv4Address() { + return true; + } + + /** + * Method setIpAddress + * + * @param hostName a String + * + * @throws UnknownHostException + * + */ + public void setIpAddress(String hostName) throws UnknownHostException { + _addr.setIpAddress(hostName); + } + + /** + * Method getIpName + * + * @return a String + * + * @throws UnknownHostException + * + */ + public String getIpName() throws UnknownHostException { + return (_addr.getIpName()); + } + + /** + * Method getIpAddress + * + * @return an int + * + */ + public int getIpAddress() { + return (_addr.getIpAddress()); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + return (_objHdr.getDataLength()); + } + + protected COPSIpv4Interface() { + _objHdr = new COPSObjHeader(); + _objHdr.setCType((byte) 1); + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + + protected COPSIpv4Interface(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + byte[] buf = new byte[4]; + System.arraycopy(dataPtr,4,buf,0,4); + + _addr.parse(buf); + + _ifindex |= ((int) dataPtr[8]) << 24; + _ifindex |= ((int) dataPtr[9]) << 16; + _ifindex |= ((int) dataPtr[10]) << 8; + _ifindex |= ((int) dataPtr[11]) & 0xFF; + + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + +} + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4LastPdpAddr.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4LastPdpAddr.java new file mode 100644 index 0000000..a392b19 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4LastPdpAddr.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * COPS IPv4 Last PDP Address + * + * @version COPSIpv4LastPdpAddr.java, v 1.00 2003 + * + */ +public class COPSIpv4LastPdpAddr extends COPSIpv4PdpAddress { + + public COPSIpv4LastPdpAddr() { + super(); + _objHdr.setCNum(COPSObjHeader.COPS_LAST_PDP_ADDR); + } + + public COPSIpv4LastPdpAddr(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method isLastPdpAddress + * + * @return a boolean + * + */ + public boolean isLastPdpAddress() { + return true; + }; + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("Ipv4PdpAddress" + "\n").getBytes()); + os.write(new String("Address: " + _addr.getIpName() + "\n").getBytes()); + os.write(new String("Port: " + _tcpPort + "\n").getBytes()); + } +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4OutInterface.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4OutInterface.java new file mode 100644 index 0000000..3178a93 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4OutInterface.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; + +/** + * COPS IPv4 Output Interface + * + * @version COPSIpv4OutInterface.java, v 1.00 2003 + * + */ +public class COPSIpv4OutInterface extends COPSIpv4Interface { + public COPSIpv4OutInterface() { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_ININTF); + } + + public COPSIpv4OutInterface(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method className + * + * @return a String + * + */ + public String className() { + return "COPSIpv4OutInterface"; + } + + /** + * Method isInInterface + * + * @return a boolean + * + */ + public boolean isInInterface() { + return true; + } + + /** + * Writes data to given socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + } + +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4PdpAddress.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4PdpAddress.java new file mode 100644 index 0000000..5c8d1df --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv4PdpAddress.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * COPS IPv4 PDP Address + * + * @version COPSIpv4PdpAddress.java, v 1.00 2003 + * + */ +abstract public class COPSIpv4PdpAddress extends COPSPdpAddress { + + protected COPSObjHeader _objHdr; + protected COPSIpv4Address _addr; + private short _reserved; + protected short _tcpPort; + + protected COPSIpv4PdpAddress() { + _addr = new COPSIpv4Address(); + _objHdr = new COPSObjHeader(); + _objHdr.setCType((byte) 1); + // _objHdr.setDataLength((short) _addr.getDataLength() + sizeof(u_int32_t)); + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + + protected COPSIpv4PdpAddress(byte[] dataPtr) { + _addr = new COPSIpv4Address(); + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + byte[] buf = new byte[4]; + System.arraycopy(dataPtr,2,buf,0,4); + _addr.parse(buf); + + _reserved |= ((short) dataPtr[8]) << 8; + _reserved |= ((short) dataPtr[9]) & 0xFF; + _tcpPort |= ((short) dataPtr[10]) << 8; + _tcpPort |= ((short) dataPtr[11]) & 0xFF; + + // _objHdr.setDataLength(_addr.getDataLength() + sizeof(u_int32_t)); + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + + /** + * Method setIpAddress + * + * @param hostName a String + * + * @throws UnknownHostException + * + */ + public void setIpAddress(String hostName) throws UnknownHostException { + _addr.setIpAddress(hostName); + } + + /** + * Method setTcpPort + * + * @param port a short + * + */ + public void setTcpPort(short port) { + _tcpPort = port; + } + + /** + * Method getIpName + * + * @return a String + * + * @throws UnknownHostException + * + */ + public String getIpName() throws UnknownHostException { + return (_addr.getIpName()); + } + + /** + * Method getTcpPort + * + * @return a short + * + */ + short getTcpPort() { + return _tcpPort; + }; + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + return (_objHdr.getDataLength()); + } + + /** + * Method isIpv6PdpAddress + * + * @return a boolean + * + */ + public boolean isIpv6PdpAddress() { + return true; + } + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // + _objHdr.writeData(id); + _addr.writeData(id); + + byte[] buf = new byte[4]; + buf[0] = (byte) (_reserved & 0xFF); + buf[1] = (byte) (_reserved << 8); + buf[2] = (byte) (_tcpPort & 0xFF); + buf[3] = (byte) (_tcpPort << 8); + + COPSUtil.writeData(id, buf, 4); + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6Address.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6Address.java new file mode 100644 index 0000000..0364359 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6Address.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * COPS IPv6 Address + * + * @version COPSIpv6Address.java, v 1.00 2003 + * + */ +public class COPSIpv6Address { + + private byte[] _addr; + + public COPSIpv6Address() { + _addr = new byte[16]; + } + + public COPSIpv6Address(String hostName) throws UnknownHostException { + setIpAddress(hostName); + } + + /** + * Method setIpAddress + * + * @param hostName a String + * + * @throws UnknownHostException + * + */ + public void setIpAddress(String hostName) throws UnknownHostException { + _addr = InetAddress.getByName(hostName).getAddress(); + } + + /** + * Method getIpName + * + * @return a String + * + * @throws UnknownHostException + * + */ + public String getIpName() throws UnknownHostException { + return InetAddress.getByAddress(_addr).getHostName(); + } + + /** + * Method parse + * + * @param dataPtr a byte[] + * + */ + public void parse(byte[] dataPtr) { + new ByteArrayInputStream(dataPtr).read(_addr,0,16); + } + + /** + * Method getDataLength + * + * @return a short + * + */ + public short getDataLength() { + return (16); + } + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + COPSUtil.writeData(id, _addr, 16); + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6InInterface.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6InInterface.java new file mode 100644 index 0000000..068c897 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6InInterface.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; + +/** + * COPS IPv6 Input Interface + * + * @version COPSIpv6InInterface.java, v 1.00 2003 + * + */ +public class COPSIpv6InInterface extends COPSIpv6Interface { + public COPSIpv6InInterface() { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_ININTF); + } + + public COPSIpv6InInterface(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method className + * + * @return a String + * + */ + public String className() { + return "COPSIpv6InInterface"; + } + + /** + * Method isInInterface + * + * @return a boolean + * + */ + public boolean isInInterface() { + return true; + } + + /** + * Writes data to given socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + } +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6Interface.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6Interface.java new file mode 100644 index 0000000..d1214a0 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6Interface.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.net.UnknownHostException; + +/** + * COPS IPv6 Interface + * + * @version COPSIpv6Interface.java, v 1.00 2003 + * + */ +public abstract class COPSIpv6Interface extends COPSInterface { + + /** + * Method isIpv6Address + * + * @return a boolean + * + */ + public boolean isIpv6Address() { + return true; + } + + /** + * Method setIpAddress + * + * @param hostName a String + * + * @throws UnknownHostException + * + */ + public void setIpAddress(String hostName) throws UnknownHostException { + _addr.setIpAddress(hostName); + } + + /** + * Method getIpName + * + * @return a String + * + * @throws UnknownHostException + * + */ + public String getIpName() throws UnknownHostException { + return (_addr.getIpName()); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + return (_objHdr.getDataLength()); + } + + protected COPSIpv6Interface() { + _objHdr = new COPSObjHeader(); + _objHdr.setCType((byte) 2); + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + + protected COPSIpv6Interface(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + byte[] buf = new byte[4]; + System.arraycopy(dataPtr,4,buf,0,16); + + _addr.parse(buf); + + _ifindex |= ((int) dataPtr[20]) << 24; + _ifindex |= ((int) dataPtr[21]) << 16; + _ifindex |= ((int) dataPtr[22]) << 8; + _ifindex |= ((int) dataPtr[23]) & 0xFF; + + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + + protected COPSObjHeader _objHdr; + private COPSIpv6Address _addr; + private int _ifindex; +} + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6LastPdpAddr.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6LastPdpAddr.java new file mode 100644 index 0000000..f0d52bb --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6LastPdpAddr.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * COPS IPv6 Last PDP Address + * + * @version COPSIpv6LastPdpAddr.java, v 1.00 2003 + * + */ +public class COPSIpv6LastPdpAddr extends COPSIpv6PdpAddress { + + public COPSIpv6LastPdpAddr() { + super(); + _objHdr.setCNum(COPSObjHeader.COPS_LAST_PDP_ADDR); + } + + public COPSIpv6LastPdpAddr(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method isLastPdpAddress + * + * @return a boolean + * + */ + public boolean isLastPdpAddress() { + return true; + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("Ipv6PdpAddress" + "\n").getBytes()); + os.write(new String("Address: " + _addr.getIpName() + "\n").getBytes()); + os.write(new String("Port: " + _tcpPort + "\n").getBytes()); + } +}; diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6OutInterface.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6OutInterface.java new file mode 100644 index 0000000..bb1f641 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6OutInterface.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; + +/** + * COPS IPv6 Output Interface + * + * @version COPSIpv6OutInterface.java, v 1.00 2003 + * + */ +public class COPSIpv6OutInterface extends COPSIpv6Interface { + public COPSIpv6OutInterface() { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_ININTF); + } + + public COPSIpv6OutInterface(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method className + * + * @return a String + * + */ + public String className() { + return "COPSIpv6OutInterface"; + } + + /** + * Method isInInterface + * + * @return a boolean + * + */ + public boolean isInInterface() { + return true; + } + + /** + * Writes data to given socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6PdpAddress.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6PdpAddress.java new file mode 100644 index 0000000..f46ff04 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSIpv6PdpAddress.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * COPS IPv6 PDP Address + * + * @version COPSIpv6PdpAddress.java, v 1.00 2003 + * + */ +abstract public class COPSIpv6PdpAddress extends COPSPdpAddress { + + protected COPSObjHeader _objHdr; + protected COPSIpv6Address _addr; + private short _reserved; + protected short _tcpPort; + + protected COPSIpv6PdpAddress() { + _addr = new COPSIpv6Address(); + _objHdr = new COPSObjHeader(); + _objHdr.setCType((byte) 2); + // _objHdr.setDataLength((short) _addr.getDataLength() + sizeof(u_int32_t)); + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + + protected COPSIpv6PdpAddress(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + byte[] buf = new byte[16]; + System.arraycopy(dataPtr,2,buf,0,16); + _addr.parse(buf); + + _reserved |= ((short) dataPtr[20]) << 8; + _reserved |= ((short) dataPtr[21]) & 0xFF; + _tcpPort |= ((short) dataPtr[22]) << 8; + _tcpPort |= ((short) dataPtr[23]) & 0xFF; + + // _objHdr.setDataLength(_addr.getDataLength() + sizeof(u_int32_t)); + _objHdr.setDataLength((short) (_addr.getDataLength() + 4)); + } + + /** + * Method setIpAddress + * + * @param hostName a String + * + * @throws UnknownHostException + * + */ + public void setIpAddress(String hostName) throws UnknownHostException { + _addr.setIpAddress(hostName); + } + + /** + * Method setTcpPort + * + * @param port a short + * + */ + public void setTcpPort(short port) { + _tcpPort = port; + } + + /** + * Method getIpName + * + * @return a String + * + * @throws UnknownHostException + * + */ + public String getIpName() throws UnknownHostException { + return (_addr.getIpName()); + } + + /** + * Method getTcpPort + * + * @return a short + * + */ + short getTcpPort() { + return _tcpPort; + }; + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + return (_objHdr.getDataLength()); + } + + /** + * Method isIpv6PdpAddress + * + * @return a boolean + * + */ + public boolean isIpv6PdpAddress() { + return true; + } + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // + _objHdr.writeData(id); + _addr.writeData(id); + + byte[] buf = new byte[4]; + buf[0] = (byte) (_reserved >> 8); + buf[1] = (byte) _reserved; + buf[2] = (byte) (_tcpPort >> 8); + buf[3] = (byte) _tcpPort ; + + COPSUtil.writeData(id, buf, 4); + } +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSKAMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSKAMsg.java new file mode 100644 index 0000000..17abb33 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSKAMsg.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Keep Alive Message + * + * @version COPSKAMsg.java, v 1.00 2003 + * + */ +public class COPSKAMsg extends COPSMsg { + + /* COPSHeader coming from base class */ + private COPSIntegrity _integrity; + + public COPSKAMsg() { + _integrity = null; + } + + protected COPSKAMsg(byte[] data) throws COPSException { + _integrity = null; + parse(data); + } + + /** Checks the sanity of COPS message and throw an + * COPSBadDataException when data is bad. + */ + public void checkSanity() throws COPSException { + //The client type in the header MUST always be set to 0 + //as KA is used for connection verification.RFC 2748 + if ((_hdr == null) && (_hdr.getClientType() != 0)) + throw new COPSException("Bad message format"); + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_KA) + throw new COPSException ("Error Header (no COPS_OP_KA)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add Integrity objects + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * Returns true if it has Integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + }; + + /** + * Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return (_integrity); + } + + /** + * Writes data to given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null) _hdr.writeData(id); + if (_integrity != null) _integrity.writeData(id); + } + + /** + * Method parse + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + super.parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format, unknown object type"); + } + } + } + checkSanity(); + } + + /** + * Method parse + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + if (hdr.getOpCode() != COPSHeader.COPS_OP_KA) + throw new COPSException("Error Header"); + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + private void setMsgLength() throws COPSException { + short len = 0; + if (_integrity != null) len += _integrity.getDataLength(); + _hdr.setMsgLength(len); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_integrity != null) { + _integrity.dump(os); + } + } +} + + + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSKATimer.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSKATimer.java new file mode 100644 index 0000000..63c4eab --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSKATimer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Keep Alive Timer + * + * @version COPSKATimer.java, v 1.00 2003 + * + */ +public class COPSKATimer extends COPSTimer { + + public COPSKATimer() { + super ((short) 1); + _objHdr.setCNum(COPSObjHeader.COPS_KA); + _objHdr.setCType((byte) 1); + } + + /// + public COPSKATimer(short timeVal) { + super(timeVal); + _objHdr.setCNum(COPSObjHeader.COPS_KA); + _objHdr.setCType((byte) 1); + } + + /** + * Method isKATimer + * + * @return a boolean + * + */ + public boolean isKATimer() { + return true; + } + + protected COPSKATimer(byte[] dataPtr) { + super (dataPtr); + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSLPDPDecision.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSLPDPDecision.java new file mode 100644 index 0000000..cd4a7ff --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSLPDPDecision.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS LPDP Decision Object + * + * @version COPSLPDPDecision.java, v 1.00 2003 + * + */ +public class COPSLPDPDecision extends COPSDecision { + + /** + Constructor to create a Local Decision object. + */ + public COPSLPDPDecision(byte cType) { + super (cType); + _objHdr.setCNum(COPSObjHeader.COPS_LPDP_DEC); + } + + public COPSLPDPDecision() { + super (); + _objHdr.setCNum(COPSObjHeader.COPS_LPDP_DEC); + } + + /** + * Method isLocalDecision + * + * @return a boolean + * + */ + public boolean isLocalDecision() { + return true; + } + + protected COPSLPDPDecision(byte[] data) { + super (data); + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSMsg.java new file mode 100644 index 0000000..2c492f3 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSMsg.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Message + * + * @version COPSMsg.java, v 1.00 2003 + * + */ +abstract public class COPSMsg { + + protected COPSHeader _hdr; + protected int _dataLength; + protected int _dataStart; + + /** + * Method getHeader + * + * @return a COPSHeader + * + */ + public COPSHeader getHeader() { + return _hdr; + } + + /** + * Method writeData + * + * @param id a Socket + * + * @throws IOException + * + */ + public abstract void writeData(Socket id) throws IOException; + + /** + * Method getMsgLength + * + * @return an int + * + */ + public int getMsgLength() { + return _hdr.getMsgLength(); + } + + /** + * Method parse + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected abstract void parse(COPSHeader hdr, byte[] data) throws COPSException; + + /** + * Method parse + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected abstract void parse(byte[] data) throws COPSException; + + /** + * Method parseHeader + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parseHeader(byte[] data) throws COPSException { + _dataLength = 0; + _dataStart = 0; + if (_hdr == null) { + // _hdr = new COPSHeader(COPSHeader.COPS_OP_CAT); + _hdr = new COPSHeader(data); + _dataStart += 8; + _dataLength = _hdr.getMsgLength(); + } else { + //header is already read + _dataLength = _hdr.getMsgLength() - 8; + } + + //validate the message length + //Should fill on the 32bit boundary + if ((_hdr.getMsgLength() % 4 != 0)) { + throw new COPSException("Bad message format: COPS message is not on 32 bit bounday"); + } + } + + /** Checks the sanity of COPS message and throw an + COPSBadDataException when data is bad. + */ + public abstract void checkSanity()throws COPSException; + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + os.write(new String("COPS Message").getBytes()); + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSMsgParser.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSMsgParser.java new file mode 100644 index 0000000..04a4aff --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSMsgParser.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +/** + * COPS Message Parser + * + * @version COPSMsgParser.java, v 1.00 2003 + * + */ + +// import org.umu.cops.common.COPSDebug; + +public class COPSMsgParser { + /// + public COPSMsgParser() { + + } + + /** Parses the given COPS data and returns a COPSMsg object + * with COPS object filed in.The COPSMsg object is allocated in the + * call and it is the responsibility of the caller to free the memory + * + * @param data a byte[] + * + * @return a COPSMsg + * + * @throws COPSException + * + */ + public COPSMsg parse(byte[] data) throws COPSException { + COPSHeader hdr = new COPSHeader(data); + + byte[] buf = new byte[data.length - 8]; + System.arraycopy(data,8,buf,0,data.length - 8); + + return (parse(hdr, buf)); + } + + /** + * Parse the message with given header , the data is pointing + * to the data following the header + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @return a COPSMsg + * + * @throws COPSException + * + */ + public COPSMsg parse(COPSHeader hdr, byte[] data) throws COPSException { + COPSMsg copsMsg = null; + short cCode = hdr.getOpCode(); + switch (cCode) { + case COPSHeader.COPS_OP_REQ: { + // COPSDebug.out(getClass().getName(), "Creating REQ msg"); + copsMsg = new COPSReqMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_DEC: { + // COPSDebug.out(getClass().getName(), "Creating DEC msg"); + copsMsg = new COPSDecisionMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_RPT: { + // COPSDebug.out(getClass().getName(), "Creating RPT msg"); + copsMsg = new COPSReportMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_DRQ: { + // COPSDebug.out(getClass().getName(), "Creating DRQ msg"); + copsMsg = new COPSDeleteMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_OPN: { + // COPSDebug.out(getClass().getName(), "Creating Client-Open msg"); + copsMsg = new COPSClientOpenMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_CAT: { + // COPSDebug.out(getClass().getName(), "Creating Client-Accept msg"); + copsMsg = new COPSClientAcceptMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_CC: { + // COPSDebug.out(getClass().getName(), "Creating Client-Close msg"); + copsMsg = new COPSClientCloseMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_KA: { + // COPSDebug.out(getClass().getName(), "Creating KA msg"); + copsMsg = new COPSKAMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_SSQ: { + // COPSDebug.out(getClass().getName(), "Creating Sync-State Request msg"); + copsMsg = new COPSSyncStateMsg(); + copsMsg.parse(hdr, data); + } + break; + case COPSHeader.COPS_OP_SSC: { + // COPSDebug.out(getClass().getName(), "Creating Sync-State Complete msg"); + copsMsg = new COPSSyncStateMsg(); + copsMsg.parse(hdr, data); + } + break; + default: + // COPSDebug.out(getClass().getName(), "Unknown message type"); + break; + } + + + // if(copsMsg != null) + // try { copsMsg.dump(COPSDebug.out); } catch (Exception e) {}; + + return copsMsg; + } +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSObjBase.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSObjBase.java new file mode 100644 index 0000000..bd05be2 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSObjBase.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; +import java.util.Arrays; + +/** + * COPS Object + * + * @version COPSObjBase.java, v 1.00 2003 + * + */ +public abstract class COPSObjBase { + /** + * Add padding in the data, if the data does not fall on 32-bit boundary + * + * @param len an int + * + * @return a COPSData + * + */ + static COPSData getPadding(int len) { + byte[] padBuf = new byte[len]; + Arrays.fill(padBuf, (byte) 0); + COPSData d = new COPSData(padBuf, 0, len); + return d; + } + + /** + * Writes data to a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public abstract void writeData(Socket id) throws IOException; + + /** + * Method getDataLength + * + * @return a short + * + */ + short getDataLength() { + return 0; + } + + /** + * Method isCOPSHeader + * + * @return a boolean + * + */ + boolean isCOPSHeader() { + return false; + } + + /** + * Method isClientHandle + * + * @return a boolean + * + */ + boolean isClientHandle() { + return false; + } + + /** + * Method isContext + * + * @return a boolean + * + */ + boolean isContext() { + return false; + } + + /** + * Method isInterface + * + * @return a boolean + * + */ + boolean isInterface() { + return false; + } + + /** + * Method isDecision + * + * @return a boolean + * + */ + boolean isDecision() { + return false; + } + + /** + * Method isLocalDecision + * + * @return a boolean + * + */ + boolean isLocalDecision() { + return false; + } + + /** + * Method isReport + * + * @return a boolean + * + */ + boolean isReport() { + return false; + } + + /** + * Method isError + * + * @return a boolean + * + */ + boolean isError() { + return false; + } + + /** + * Method isTimer + * + * @return a boolean + * + */ + boolean isTimer() { + return false; + } + + /** + * Method isPepId + * + * @return a boolean + * + */ + boolean isPepId() { + return false; + } + + /** + * Method isReason + * + * @return a boolean + * + */ + boolean isReason() { + return false; + } + + /** + * Method isPdpAddress + * + * @return a boolean + * + */ + boolean isPdpAddress() { + return false; + } + + /** + * Method isClientSI + * + * @return a boolean + * + */ + boolean isClientSI() { + return false; + } + + /** + * Method isMessageIntegrity + * + * @return a boolean + * + */ + boolean isMessageIntegrity() { + return false; + } + +}; + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSObjHeader.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSObjHeader.java new file mode 100644 index 0000000..ae24233 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSObjHeader.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Object Header + * + * @version COPSObjHeader.java, v 1.00 2003 + * + */ +public class COPSObjHeader extends COPSObjBase { + + public final static byte COPS_HANDLE = 1; + public final static byte COPS_CONTEXT = 2; + public final static byte COPS_ININTF = 3; + public final static byte COPS_OUTINTF = 4; + public final static byte COPS_REASON_CODE = 5; + public final static byte COPS_DEC = 6; + public final static byte COPS_LPDP_DEC = 7; + public final static byte COPS_ERROR = 8; + public final static byte COPS_CSI = 9; + public final static byte COPS_KA = 10; + public final static byte COPS_PEPID = 11; + public final static byte COPS_RPT = 12; + public final static byte COPS_PDP_REDIR = 13; + public final static byte COPS_LAST_PDP_ADDR = 14; + public final static byte COPS_ACCT_TIMER = 15; + public final static byte COPS_MSG_INTEGRITY = 16; + + private short _len; + private byte _cNum; + private byte _cType; + + public COPSObjHeader(byte cNum, byte cType) { + _len = 4; + _cNum = cNum; + _cType = cType; + } + + public COPSObjHeader() { + _len = 4; + _cNum = 0; + _cType = 0; + } + + protected COPSObjHeader(byte[] data) { + parse(data); + } + + /** + * Get the data length in number of octets + * + * @return a short + * + */ + public short getDataLength() { + return _len; + }; + + /** + * Get the class information identifier cNum + * + * @return a byte + * + */ + public byte getCNum() { + return _cNum; + }; + + /** + * Get the type per cNum + * + * @return a byte + * + */ + public byte getCType() { + return _cType; + }; + + /** + * Get stringified CNum + * + * @return a String + * + */ + public String getStrCNum() { + switch (getCNum()) { + case COPS_HANDLE: + return ("Client-handle"); + case COPS_CONTEXT: + return ("Context"); + case COPS_ININTF: + return ("In-Interface"); + case COPS_OUTINTF: + return ("Out-Interface"); + case COPS_REASON_CODE: + return ("Reason"); + case COPS_DEC: + return ("Decision"); + case COPS_LPDP_DEC: + return ("Local-Decision"); + case COPS_ERROR: + return ("Error"); + case COPS_CSI: + return ("Client-SI"); + case COPS_KA: + return ("KA-timer"); + case COPS_PEPID: + return ("PEP-id"); + case COPS_RPT: + return ("Report"); + case COPS_PDP_REDIR: + return ("Redirect PDP addr"); + case COPS_LAST_PDP_ADDR: + return ("Last PDP addr"); + case COPS_ACCT_TIMER: + return ("Account-Timer"); + case COPS_MSG_INTEGRITY: + return ("Message-Integrity"); + default: + return ("Unknown"); + } + } + + /** + * Set the obj length, the length is the length of the data following + * the object header.The length of the object header (4 bytes) is added + * to the length passed. + * + * @param len a short + * + */ + public void setDataLength(short len) { + //Add the length of the header also + _len = (short) (len + 4); + } + + /** + * Set the class of information cNum + * + * @param cNum a byte + * + */ + public void setCNum(byte cNum) { + _cNum = cNum; + } ; + + /** + * Set the type defined per cNum + * + * @param cType a byte + * + */ + public void setCType(byte cType) { + _cType = cType; + } ; + + /** + * Method checkDataLength + * + * @throws COPSException + * + */ + public void checkDataLength() throws COPSException { + + } + + /** + * Writes data to a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + byte[] buf = new byte[4]; + + buf[0] = (byte) (_len >> 8); + buf[1] = (byte) _len; + buf[2] = (byte) _cNum; + buf[3] = (byte) _cType; + + COPSUtil.writeData(id, buf, 4); + } + + /** + * Method parse + * + * @param data a byte[] + * + */ + public void parse(byte[] data) { + _len = 0; + _len |= ((short) data[0]) << 8; + _len |= ((short) data[1]) & 0xFF; + _cNum |= data[2]; + _cType |= data[3]; + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + os.write(new String("**" + getStrCNum() + "**" + "\n").getBytes()); + os.write(new String("Length: " + _len + "\n").getBytes()); + os.write(new String("C-num: " + _cNum + "\n").getBytes()); + os.write(new String("C-type: " + _cType + "\n").getBytes()); + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPdpAddress.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPdpAddress.java new file mode 100644 index 0000000..f202364 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPdpAddress.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * COPS PDP Address + * + * @version COPSPdpAddress.java, v 1.00 2003 + * + */ +abstract public class COPSPdpAddress extends COPSObjBase { + + /** + * Method isPdpAddress + * + * @return a boolean + * + */ + public boolean isPdpAddress() { + return true; + }; + + /** + * Method isIpv4PdpAddress + * + * @return a boolean + * + */ + public boolean isIpv4PdpAddress() { + return false; + }; + + /** + * Method isIpv6PdpAddress + * + * @return a boolean + * + */ + public boolean isIpv6PdpAddress() { + return false; + }; + + /** + * Method isLastPdpAddress + * + * @return a boolean + * + */ + public boolean isLastPdpAddress() { + return false; + }; + + /** + * Method isPdpredirectAddress + * + * @return a boolean + * + */ + public boolean isPdpredirectAddress() { + return false; + }; + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + abstract public void dump(OutputStream os) throws IOException; +}; + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPepId.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPepId.java new file mode 100644 index 0000000..df02586 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPepId.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS PEP Identification Object + * + * @version COPSPepId.java, v 1.00 2003 + * + */ +public class COPSPepId extends COPSObjBase { + + COPSObjHeader _objHdr; + COPSData _data; + COPSData _padding; + + public COPSPepId() { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_PEPID); + _objHdr.setCType((byte) 1); + } + + protected COPSPepId(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + //Get the length of data following the obj header + short dLen = (short) (_objHdr.getDataLength() - 4); + COPSData d = new COPSData (dataPtr, 4, dLen); + setData(d); + } + + /** + * Method setData + * + * @param data a COPSData + * + */ + public void setData(COPSData data) { + _data = data; + if (_data.length() % 4 != 0) { + int padLen = 4 - _data.length() % 4; + _padding = getPadding(padLen); + } + _objHdr.setDataLength((short)_data.length()); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + int lpadding = 0; + if (_padding != null) lpadding = _padding.length(); + return ((short) (_objHdr.getDataLength() + lpadding)); + } + + /** + * Method getData + * + * @return a COPSData + * + */ + public COPSData getData() { + return _data; + }; + + /** + * Method isPepId + * + * @return a boolean + * + */ + public boolean isPepId() { + return true; + }; + + /** + * Write data to given netwrok socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + COPSUtil.writeData(id, _data.getData(), _data.length()); + if (_padding != null) { + COPSUtil.writeData(id, _padding.getData(), _padding.length()); + } + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("PEPID: " + _data.str() + "\n").getBytes()); + } +} + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrClassError.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrClassError.java new file mode 100644 index 0000000..c86a99e --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrClassError.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Provisioning Class Error + * + * @version COPSPrClassError.java, v 1.00 2003 + * + */ +public class COPSPrClassError extends COPSPrError { + + public final static byte C_spaceExhausted = 1; + public final static byte C_instanceInvalid = 2; + public final static byte C_attrValueInvalid = 3; + public final static byte C_attrValueSupLimited = 4; + public final static byte C_attrEnumSupLimited = 5; + public final static byte C_attrMaxLengthExceeded = 6; + public final static byte C_attrRefUnknown = 7; + public final static byte C_notifyOnly = 8; + public final static byte C_unknownPrc = 9; + public final static byte C_tooFewAttrs = 10; + public final static byte C_invalidAttrType = 11; + public final static byte C_deletedInRef = 12; + public final static byte C_specificError = 13; + public final static byte C_errmax = 14; + + private final static String CerrTable[] = { + "Reserved", + "No more instances may currently be installed in the given class", + "Invalid class instance", + "Invalid attribute value", + "The value for attribute not currently supported by the device", + "The enumeration for attribute not currently supported by the device", + "Attribute length exceeds device limitations", + "Unknown attribute reference", + "Only supported for use by request or report", + "Class not supported by PEP", + "Too few attributes", + "Invalid attribute type", + "Reference to deleted instance", + "PRC specific error, check subcode for more details" + }; + + public COPSPrClassError(short eCode, short eSubCode) { + super (eCode, eSubCode); + _sNum = COPSPrObjBase.PR_CPERR; + _sType = COPSPrObjBase.PR_BER; + } + + /** + Parse the data and create a PrClassError object + */ + protected COPSPrClassError(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method isPRCClassError + * + * @return a boolean + * + */ + public boolean isPRCClassError() { + return true; + } + + /** + * Method strError + * + * @return a String + * + */ + public String strError() { + return CerrTable[_errCode]; + }; +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrEPD.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrEPD.java new file mode 100644 index 0000000..74f5dd0 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrEPD.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Provisioning EPD + * + * @version COPSPrEPD.java, v 1.00 2003 + * + */ +public class COPSPrEPD extends COPSPrObjBase { + + public COPSPrEPD() { + _sNum = COPSPrObjBase.PR_EPD; + _sType = COPSPrObjBase.PR_XML; + } + + /** + * Method isEncodedInstanceData + * + * @return a boolean + * + */ + public boolean isEncodedInstanceData() { + return true; + } + + /** + Parse the data and create a PrEPD object + */ + protected COPSPrEPD(byte[] dataPtr) { + super(dataPtr); + } + + +}; + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrError.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrError.java new file mode 100644 index 0000000..467f9bf --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrError.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; + +/** + * COPS Provisioning Error + * + * @version COPSPrError.java, v 1.00 2003 + * + */ +public class COPSPrError extends COPSPrObjBase { + + protected short _errCode; + protected short _errSubCode; + + public COPSPrError(short eCode, short eSubCode) { + _errCode = eCode; + _errSubCode = eSubCode; + _len = 8; + } + + /** + Parse the data and create a PrGlobalError object + */ + protected COPSPrError(byte[] dataPtr) { + _dataRep = null; + + _len |= ((short) dataPtr[0]) << 8; + _len |= ((short) dataPtr[1]) & 0xFF; + + _sNum |= ((short) dataPtr[2]) << 8; + _sNum |= ((short) dataPtr[3]) & 0xFF; + + _errCode |= ((short) dataPtr[4]) << 8; + _errCode |= ((short) dataPtr[5]) & 0xFF; + + _errSubCode |= ((short) dataPtr[6]) << 8; + _errSubCode |= ((short) dataPtr[7]) & 0xFF; + } + + /** + * Method strError + * + * @return a String + * + */ + public String strError() { + return "Error"; + } + + /** + * Method setData + * + * @param data a COPSData + * + */ + public void setData(COPSData data) { } ; + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + byte[] dataRep = getDataRep(); + COPSUtil.writeData(id, dataRep, dataRep.length); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + return 8; + } + + /** + * Method getDataRep + * + * @return a byte[] + * + */ + public byte[] getDataRep() { + _dataRep = new byte[getDataLength()]; + + _dataRep[0] = (byte) (_len >> 8); + _dataRep[1] = (byte) _len; + _dataRep[2] = (byte) (_sNum >> 8); + _dataRep[3] = (byte) _sNum; + _dataRep[4] = (byte) (_errCode >> 8); + _dataRep[5] = (byte) _errCode; + _dataRep[6] = (byte) (_errSubCode >> 8); + _dataRep[7] = (byte) _errSubCode; + + return _dataRep; + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrErrorPRID.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrErrorPRID.java new file mode 100644 index 0000000..132c587 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrErrorPRID.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Provisioning Error PRID + * + * @version COPSPrErrorPRID.java, v 1.00 2003 + * + */ +public class COPSPrErrorPRID extends COPSPrObjBase { + + public COPSPrErrorPRID() { + _sNum = COPSPrObjBase.PR_IDERR; + _sType = COPSPrObjBase.PR_BER; + } + + /** + Parse the data and create a PrErrorPRID object + */ + protected COPSPrErrorPRID(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method isErrorPRID + * + * @return a boolean + * + */ + public boolean isErrorPRID() { + return true; + } + +} diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrGlobalError.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrGlobalError.java new file mode 100644 index 0000000..d44848e --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrGlobalError.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Provisioning Global Error + * + * @version COPSPrGlobalError.java, v 1.00 2003 + * + */ +public class COPSPrGlobalError extends COPSPrError { + + public final static byte G_availMemoryLow = 1; + public final static byte G_availMemoryExhausted = 2; + public final static byte G_unknownASN1Tag = 3; + public final static byte G_maxMsgSizeExceeded = 4; + public final static byte G_unknownError = 5; + public final static byte G_maxReqStateOpen = 6; + public final static byte G_invalidASN1Length = 7; + public final static byte G_invalidObjPad = 8; + public final static byte G_unknownPIBData = 9; + public final static byte G_unknownCOPSPrObj = 10; + public final static byte G_malformedDec = 11; + public final static byte G_errmax = 12; + + + private final static String GerrTable[] = { + "Reserved", + "Available memory low", + "Available memory exhausted", + "Unknown ASN.1 tag", + "Max. message size exceeded", + "Unknown error", + "No more Request-states can be created by the PEP", + "ASN.1 object length was incorrect", + "Object was not properly padded", + "Unknown PIB data", + "Unknown COPS-PR object", + "Melformed decision" + }; + + /// + COPSPrGlobalError(short eCode, short eSubCode) { + super(eCode, eSubCode); + _sNum = COPSPrObjBase.PR_GPERR; + _sType = COPSPrObjBase.PR_BER; + } + + /** + Parse the data and create a PrGlobalError object + */ + protected COPSPrGlobalError(byte[] dataPtr) { + super(dataPtr); + } + + + /** + * Method isGlobalPrError + * + * @return a boolean + * + */ + public boolean isGlobalPrError() { + return true; + } + + /** + * Method strError + * + * @return a String + * + */ + public String strError() { + return GerrTable[_errCode]; + }; + +}; + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrID.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrID.java new file mode 100644 index 0000000..8332d60 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrID.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Provisioning ID + * + * @version COPSPrID.java, v 1.00 2003 + * + */ +public class COPSPrID extends COPSPrObjBase { + + public COPSPrID() { + _sNum = COPSPrObjBase.PR_PRID; + _sType = COPSPrObjBase.PR_XML; + } + + ///Parse the data and create a PrID object + protected COPSPrID(byte[] dataPtr) { + super(dataPtr); + } + + /** + * Method isPRID + * + * @return a boolean + * + */ + public boolean isPRID() { + return true; + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrObjBase.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrObjBase.java new file mode 100644 index 0000000..7915272 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrObjBase.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; +import java.util.Arrays; + +/** + * COPS Provisioning Object Base + * + * @version COPSPrObjBase.java, v 1.01 2003 + * + */ +public class COPSPrObjBase { + public final static byte PR_PRID = 1; + public final static byte PR_PPRID = 2; + public final static byte PR_EPD = 3; + public final static byte PR_GPERR = 4; + public final static byte PR_CPERR = 5; + public final static byte PR_IDERR = 6; + + public final static byte PR_BER = 1; + public final static byte PR_XML = 2; + + protected short _len; + protected byte _sNum; + protected byte _sType; + protected COPSData _data; + protected COPSData _padding; + + protected byte[] _dataRep; + /// + protected COPSPrObjBase() { + _dataRep = null; + } + + public COPSPrObjBase(byte[] dataPtr) { + _dataRep = null; + + _len |= ((short) dataPtr[0]) << 8; + _len |= ((short) dataPtr[1]) & 0xFF; + + _sNum |= ((short) dataPtr[2]) << 8; + _sNum |= ((short) dataPtr[3]) & 0xFF; + + //Get the length of data following the obj header + short dLen = (short) (_len - 4); + COPSData d = new COPSData(dataPtr, 4, dLen); + setData(d); + } + + /** + * Add padding in the data, if the Provisioning data does + * not fall on 32-bit boundary + * + * @param len an int + * + * @return a COPSData + * + */ + public COPSData getPadding(int len) { + byte[] padBuf = new byte[len]; + Arrays.fill(padBuf, (byte) 0); + COPSData d = new COPSData(padBuf, 0, len); + return d; + } + + /** + * Method isPRID + * + * @return a boolean + * + */ + public boolean isPRID() { + return false; + }; + + /** + * Method isPRIDPrefix + * + * @return a boolean + * + */ + public boolean isPRIDPrefix() { + return false; + }; + + /** + * Method isEncodedInstanceData + * + * @return a boolean + * + */ + public boolean isEncodedInstanceData() { + return false; + }; + + /** + * Method isGlobalPrError + * + * @return a boolean + * + */ + public boolean isGlobalPrError() { + return false; + }; + + /** + * Method isPRCClassError + * + * @return a boolean + * + */ + public boolean isPRCClassError() { + return false; + }; + + /** + * Method isErrorPRID + * + * @return a boolean + * + */ + public boolean isErrorPRID() { + return false; + }; + + /** + * Method setData + * + * @param data a COPSData + * + */ + public void setData(COPSData data) { + _data = data; + if (_data.length() % 4 != 0) { + int padLen = 4 - (_data.length() % 4); + _padding = getPadding(padLen); + } + _len = (short) (_data.length() + 4); + } + + /** + * Get the class information identifier cNum + * + * @return a byte + * + */ + public byte getSNum() { + return _sNum; + }; + + /** + * Get the type per sNum + * + * @return a byte + * + */ + public byte getSType() { + return _sType; + }; + + /** + * Get stringified CNum + * + * @return a String + * + */ + public String getStrSNum() { + switch (getSNum()) { + case PR_PRID: + return ("PRID"); + case PR_PPRID: + return ("PRID Prefix"); + case PR_EPD: + return ("EPD"); + case PR_GPERR: + return ("GPERR"); + case PR_CPERR: + return ("CPERR"); + case PR_IDERR: + return ("IDERR"); + default: + return ("Unknown"); + } + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + //Header length contains the header+data length + int lpadding = 0; + if (_padding != null) lpadding = _padding.length(); + return ( (short) (_len + lpadding)); + } + + /** + * Method getData + * + * @return a COPSData + * + */ + public COPSData getData() { + return _data; + }; + + /** + * Write data on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + byte[] dataRep = getDataRep(); + COPSUtil.writeData(id, dataRep, dataRep.length); + } + + /** + * Get the binary data contained in the object + * + * @return a byte[] + * + */ + public byte[] getDataRep() { + _dataRep = new byte[getDataLength()]; + + _dataRep[0] = (byte) (_len >> 8); + _dataRep[1] = (byte) _len; + _dataRep[2] = (byte) (_sNum >> 8); + _dataRep[3] = (byte) _sNum; + + System.arraycopy(_data.getData(), 0, _dataRep, 4, _data.length()); + + if (_padding != null) { + System.arraycopy(_padding.getData(), 0, _dataRep, 4 + _data.length(), _padding.length()); + } + + return _dataRep; + } + +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrefixPrID.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrefixPrID.java new file mode 100644 index 0000000..781d8f5 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSPrefixPrID.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + + + +/** + * COPS Prefix Provisioning ID + * + * @version COPSPrefixPrID.java, v 1.00 2003 + * + */ +public class COPSPrefixPrID extends COPSPrObjBase { + + /// + public COPSPrefixPrID() { + _sNum = COPSPrObjBase.PR_PPRID; + _sType = COPSPrObjBase.PR_XML; + } + + /** + * Method isPRIDPrefix + * + * @return a boolean + * + */ + public boolean isPRIDPrefix() { + return true; + } + + /** + Parse the data and create a PrefixPrID object + */ + protected COPSPrefixPrID(byte[] dataPtr) { + super(dataPtr); + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReason.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReason.java new file mode 100644 index 0000000..25c4a46 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReason.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Reason Object (RFC 2748 pag. 12) + * + * This object specifies the reason why the request state was deleted. + * It appears in the delete request (DRQ) message. The Reason Sub-code + * field is reserved for more detailed client-specific reason codes + * defined in the corresponding documents. + * + * C-Num = 5, C-Type = 1 + * + * 0 1 2 3 + * +--------------+--------------+--------------+--------------+ + * | Reason-Code | Reason Sub-code | + * +--------------+--------------+--------------+--------------+ + * + * Reason Code: + * 1 = Unspecified + * 2 = Management + * 3 = Preempted (Another request state takes precedence) + * 4 = Tear (Used to communicate a signaled state removal) + * 5 = Timeout (Local state has timed-out) + * 6 = Route Change (Change invalidates request state) + * 7 = Insufficient Resources (No local resource available) + * 8 = PDP's Directive (PDP decision caused the delete) + * 9 = Unsupported decision (PDP decision not supported) + * 10= Synchronize Handle Unknown + * 11= Transient Handle (stateless event) + * 12= Malformed Decision (could not recover) + * 13= Unknown COPS Object from PDP: + * Sub-code (octet 2) contains unknown object's C-Num + * and (octet 3) contains unknown object's C-Type. + * + * @version COPSReason.java, v 1.00 2003 + * + */ +public class COPSReason extends COPSPrObjBase { + + public final static String[] G_msgArray = { + "Unknown.", + "Unspecified.", + "Management.", + "Preempted (Another request state takes precedence).", + "Tear (Used to communicate a signaled state removal).", + "Timeout ( Local state has timed-out).", + "Route change (Change invalidates request state).", + "Insufficient Resources.", + "PDP's Directive.", + "Unsupported decision.", + "Synchronize handle unknown.", + "Transient handle.", + "Malformed decision.", + "Unknown COPS object from PDP.", + }; + + private COPSObjHeader _objHdr; + private short _reasonCode; + private short _reasonSubCode; + + /// + public COPSReason(short reasonCode, short subCode) { + _objHdr = new COPSObjHeader(); + _reasonCode = reasonCode; + _reasonSubCode = subCode; + _objHdr.setCNum(COPSObjHeader.COPS_REASON_CODE); + _objHdr.setCType((byte) 1); + _objHdr.setDataLength((short) 4); + } + + /** + Parse data and create COPSReason object + */ + protected COPSReason(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + _reasonCode |= ((short) dataPtr[4]) << 8; + _reasonCode |= ((short) dataPtr[5]) & 0xFF; + _reasonSubCode |= ((short) dataPtr[6]) << 8; + _reasonSubCode |= ((short) dataPtr[7]) & 0xFF; + + _objHdr.setDataLength((short) 4); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + return (_objHdr.getDataLength()); + } + + /** + * Get Reason description + * + * @return a String + * + */ + public String getDescription() { + String reasonStr1; + String reasonStr2; + + ///Get the details from the error code + reasonStr1 = G_msgArray[_reasonCode]; + //TODO - defind reason sub-codes + reasonStr2 = ""; + return (reasonStr1 + ":" + reasonStr2); + } + + /** + * Always return true + * + * @return a boolean + * + */ + public boolean isReason() { + return true; + } + + /** + * Write object in network byte order to a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + + _objHdr.writeData(id); + + byte[] buf = new byte[4]; + + buf[0] = (byte) (_reasonCode >> 8); + buf[1] = (byte) _reasonCode; + buf[2] = (byte) (_reasonSubCode >> 8); + buf[3] = (byte) _reasonSubCode; + + + COPSUtil.writeData(id, buf, 4); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("Reason Code: " + _reasonCode + "\n").getBytes()); + os.write(new String("Reason Sub Code: " + _reasonSubCode + "\n").getBytes()); + } +} + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReportMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReportMsg.java new file mode 100644 index 0000000..6b1540a --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReportMsg.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Vector; + +/** + * COPS Report Message (RFC 2748 pag. 25) + * + * The RPT message is used by the PEP to communicate to the PDP its + * success or failure in carrying out the PDP's decision, or to report + * an accounting related change in state. The Report-Type specifies the + * kind of report and the optional ClientSI can carry additional + * information per Client-Type. + * + * For every DEC message containing a configuration context that is + * received by a PEP, the PEP MUST generate a corresponding Report State + * message with the Solicited Message flag set describing its success or + * failure in applying the configuration decision. In addition, + * outsourcing decisions from the PDP MAY result in a corresponding + * solicited Report State from the PEP depending on the context and the + * type of client. RPT messages solicited by decisions for a given + * Client Handle MUST set the Solicited Message flag and MUST be sent in + * the same order as their corresponding Decision messages were + * received. There MUST never be more than one Report State message + * generated with the Solicited Message flag set per Decision. + * + * The Report State may also be used to provide periodic updates of + * client specific information for accounting and state monitoring + * purposes depending on the type of the client. In such cases the + * accounting report type should be specified utilizing the appropriate + * client specific information object. + * + * ::== + * + * + * [] + * [] + * + * @version COPSReportMsg.java, v 1.00 2003 + * + */ +public class COPSReportMsg extends COPSMsg { + /* COPSHeader coming from base class */ + private COPSHandle _clientHandle; + private COPSReportType _report; + private Vector _clientSI; + private COPSIntegrity _integrity; + + public COPSReportMsg() { + _clientHandle = null; + _report = null; + _integrity = null; + _clientSI = new Vector(20); + } + + /** + Parse data and create COPSReportMsg object + */ + protected COPSReportMsg (byte[] data) throws COPSException { + _clientHandle = null; + _report = null; + _integrity = null; + parse(data); + } + + /** + * Checks the sanity of COPS message and throw an + * COPSException when data is bad. + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_clientHandle == null) || (_report == null)) + throw new COPSException("Bad message format"); + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_RPT) + throw new COPSException ("Error Header (no COPS_OP_REQ)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add Report object to the message + * + * @param report a COPSReportType + * + * @throws COPSException + * + */ + public void add (COPSReportType report) throws COPSException { + if (report == null) + throw new COPSException ("Null Handle"); + + //Message integrity object should be the very last one + //If it is already added + if (_integrity != null) + throw new COPSException ("No null Handle"); + + _report = report; + setMsgLength(); + } + + /** + * Add client handle to the message + * + * @param handle a COPSHandle + * + * @throws COPSException + * + */ + public void add (COPSHandle handle) throws COPSException { + if (handle == null) + throw new COPSException ("Null Handle"); + + //Message integrity object should be the very last one + //If it is already added + if (_integrity != null) + throw new COPSException ("No null Handle"); + + _clientHandle = handle; + setMsgLength(); + } + + /** + * Add one or more clientSI objects + * + * @param clientSI a COPSClientSI + * + * @throws COPSException + * + */ + public void add (COPSClientSI clientSI) throws COPSException { + if (clientSI == null) + throw new COPSException ("Null ClientSI"); + _clientSI.add(clientSI); + setMsgLength(); + } + + /** + * Add integrity object + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * Get client Handle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _clientHandle; + } + + /** + * Get report type + * + * @return a COPSReportType + * + */ + public COPSReportType getReport() { + return _report; + } + + /** + * Get clientSI + * + * @return a Vector + * + */ + public Vector getClientSI() { + return _clientSI; + } + + /** + * Returns true if it has Integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + } + + + /** + * Get Integrity. Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return (_integrity); + } + + /** + * Writes data to given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + //checkSanity(); + if (_hdr != null) _hdr.writeData(id); + if (_clientHandle != null) _clientHandle.writeData(id); + if (_report != null) _report.writeData(id); + + for (Enumeration e = _clientSI.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + clientSI.writeData(id); + } + + if (_integrity != null) _integrity.writeData(id); + } + + /** + * Parse data + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + super.parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_HANDLE: { + _clientHandle = new COPSHandle(buf); + _dataStart += _clientHandle.getDataLength(); + } + break; + case COPSObjHeader.COPS_RPT: { + _report = new COPSReportType(buf); + _dataStart += _report.getDataLength(); + } + break; + case COPSObjHeader.COPS_CSI: { + COPSClientSI csi = new COPSClientSI(buf); + _dataStart += csi.getDataLength(); + _clientSI.add(csi); + } + break; + + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + + default: { + throw new COPSException("Bad Message format, unknown object type"); + } + } + } + checkSanity(); + } + + /** + * Parse data + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + if (hdr.getOpCode() != COPSHeader.COPS_OP_RPT) + throw new COPSException ("Null Header"); + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + short len = 0; + if (_clientHandle != null) len += _clientHandle.getDataLength(); + if (_report != null) len += _report.getDataLength(); + + for (Enumeration e = _clientSI.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + len += clientSI.getDataLength(); + } + + if (_integrity != null) len += _integrity.getDataLength(); + _hdr.setMsgLength(len); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_clientHandle != null) + _clientHandle.dump(os); + + if (_report != null) + _report.dump(os); + + for (Enumeration e = _clientSI.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + clientSI.dump(os); + } + + if (_integrity != null) { + _integrity.dump(os); + } + } +} + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReportType.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReportType.java new file mode 100644 index 0000000..41703e7 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReportType.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Report Type (RFC 2748 pag. 16 + * + * The Type of Report on the request state associated with a handle: + * + * C-Num = 12, C-Type = 1 + * + * 0 1 2 3 + * +--------------+--------------+--------------+--------------+ + * | Report-Type | ///////////// | + * +--------------+--------------+--------------+--------------+ + * + * Report-Type: + * 1 = Success : Decision was successful at the PEP + * 2 = Failure : Decision could not be completed by PEP + * 3 = Accounting: Accounting update for an installed state + * + * + * @version COPSReportType.java, v 1.00 2003 + * + */ +public class COPSReportType extends COPSPrObjBase { + + public final static String[] msgMap = { + "Unknown", + "Success", + "Failure", + "Accounting", + }; + + private COPSObjHeader _objHdr; + private short _rType; + private short _reserved; + + public final static short SUCCESS = 1; + public final static short FAILURE = 2; + public final static short ACCT = 3; + + public COPSReportType(short rType) { + _objHdr = new COPSObjHeader(); + _objHdr.setCNum(COPSObjHeader.COPS_RPT); + _objHdr.setCType((byte) 1); + _rType = rType; + _objHdr.setDataLength((short) 4); + } + + /** + Parse data and create COPSReportType object + */ + protected COPSReportType(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + _rType |= ((short) dataPtr[4]) << 8; + _rType |= ((short) dataPtr[5]) & 0xFF; + _reserved |= ((short) dataPtr[6]) << 8; + _reserved |= ((short) dataPtr[7]) & 0xFF; + + _objHdr.setDataLength((short) 4); + } + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + return (_objHdr.getDataLength()); + } + + /** + * If it is Success, return true + * + * @return a boolean + * + */ + public boolean isSuccess() { + return (_rType == SUCCESS ); + }; + + /** + * If it is Failure, return true + * + * @return a boolean + * + */ + public boolean isFailure() { + return (_rType == FAILURE); + }; + + /** + * If it is Accounting, return true + * + * @return a boolean + * + */ + public boolean isAccounting() { + return (_rType == ACCT); + }; + + /** + * Always return true + * + * @return a boolean + * + */ + public boolean isReport() { + return true; + }; + + /** + * Write data in network byte order on a given network socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + + byte[] buf = new byte[4]; + + buf[0] = (byte) (_rType >> 8); + buf[1] = (byte) _rType; + buf[2] = (byte) (_reserved >> 8); + buf[3] = (byte) _reserved; + + COPSUtil.writeData(id, buf, 4); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("Report: " + msgMap[_rType] + "\n").getBytes()); + } +} + + + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReqMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReqMsg.java new file mode 100644 index 0000000..3f3a803 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSReqMsg.java @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +/** + * COPS Request Message (RFC 2748 pag. 22) + * + * The PEP establishes a request state client handle for which the + * remote PDP may maintain state. The remote PDP then uses this handle + * to refer to the exchanged information and decisions communicated over + * the TCP connection to a particular PEP for a given client-type. + * + * Once a stateful handle is established for a new request, any + * subsequent modifications of the request can be made using the REQ + * message specifying the previously installed handle. The PEP is + * responsible for notifying the PDP whenever its local state changes so + * the PDP's state will be able to accurately mirror the PEP's state. + * + * The format of the Request message is as follows: + * + * ::= + * + * + * [] + * [] + * [] + * [] + * [] + * + * ::= | + * + * ::= | + * + * + * ::= [] + * + * [] + * [] + * [] + * [] + * + * The context object is used to determine the context within which all + * the other objects are to be interpreted. It also is used to determine + * the kind of decision to be returned from the policy server. This + * decision might be related to admission control, resource allocation, + * object forwarding and substitution, or configuration. + * + * The interface objects are used to determine the corresponding + * interface on which a signaling protocol message was received or is + * about to be sent. They are typically used if the client is + * participating along the path of a signaling protocol or if the client + * is requesting configuration data for a particular interface. + * + * ClientSI, the client specific information object, holds the client- + * type specific data for which a policy decision needs to be made. In + * the case of configuration, the Named ClientSI may include named + * information about the module, interface, or functionality to be + * configured. The ordering of multiple ClientSIs is not important. + * + * Finally, LPDPDecision object holds information regarding the local + * decision made by the LPDP. + * + * Malformed Request messages MUST result in the PDP specifying a + * Decision message with the appropriate error code. + * + * @version COPSReqMsg.java, v 1.00 2003 + * + */ +public class COPSReqMsg extends COPSMsg { + + /* COPSHeader coming from base class */ + private COPSHandle _clientHandle; + private COPSContext _context; + private COPSInterface _inInterface; + private COPSInterface _outInterface; + private Vector _clientSIs; + private Hashtable _decisions; + private COPSIntegrity _integrity; + private COPSContext _lpdpContext; + + public COPSReqMsg() { + _clientHandle = null; + _context = null; + _inInterface = null; + _outInterface = null; + _clientSIs = new Vector(20); + _decisions = new Hashtable(); + _integrity = null; + _lpdpContext = null; + } + + /** + Parse data and create COPSReqMsg object + */ + protected COPSReqMsg(byte[] data) throws COPSException { + parse(data); + } + + /** + * Checks the sanity of COPS message and throw an + * COPSBadDataException when data is bad. + */ + public void checkSanity() throws COPSException { + if ((_hdr == null) || (_clientHandle == null) || (_context == null)) { + throw new COPSException("Bad message format"); + } + } + + /** + * Add an IN or OUT interface object + * + * @param inter a COPSInterface + * + * @throws COPSException + * + */ + public void add (COPSInterface inter) throws COPSException { + if (!(inter.isInInterface() || inter.isOutInterface())) + throw new COPSException ("No Interface"); + + //Message integrity object should be the very last one + //If it is already added + if (_integrity != null) + throw new COPSException ("Integrity should be the last one"); + + if (inter.isInInterface()) { + if (_inInterface != null) + throw new COPSException ("Object inInterface exits"); + + if (inter.isIpv4Address()) { + COPSIpv4InInterface inInter = (COPSIpv4InInterface) inter; + _inInterface = inInter; + } else { + COPSIpv6InInterface inInter = (COPSIpv6InInterface) inter; + _inInterface = inInter; + } + } else { + if (_outInterface != null) + throw new COPSException ("Object outInterface exits"); + + if (inter.isIpv4Address()) { + COPSIpv4OutInterface outInter = (COPSIpv4OutInterface) inter; + _outInterface = outInter; + } else { + COPSIpv6OutInterface outInter = (COPSIpv6OutInterface) inter; + _outInterface = outInter; + } + } + setMsgLength(); + } + + /** + * Add header to the message + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if (hdr.getOpCode() != COPSHeader.COPS_OP_REQ) + throw new COPSException ("Error Header (no COPS_OP_REQ)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add Context object to the message + * + * @param context a COPSContext + * + * @throws COPSException + * + */ + public void add (COPSContext context) throws COPSException { + if (context == null) + throw new COPSException ("Null Context"); + _context = context; + setMsgLength(); + } + + /** + * Add client handle to the message + * + * @param handle a COPSHandle + * + * @throws COPSException + * + */ + public void add (COPSHandle handle) throws COPSException { + if (handle == null) + throw new COPSException ("Null Handle"); + _clientHandle = handle; + setMsgLength(); + } + + /** + * Add one or more clientSI objects + * + * @param clientSI a COPSClientSI + * + * @throws COPSException + * + */ + public void add (COPSClientSI clientSI) throws COPSException { + if (clientSI == null) + throw new COPSException ("Null ClientSI"); + _clientSIs.add(clientSI); + setMsgLength(); + } + + /** + * Add one or more local decision object for a given decision context + * the context is optional, if null all decision object are tided to + * message context + * + * @param decision a COPSLPDPDecision + * @param context a COPSContext + * + * @throws COPSException + * + */ + public void addLocalDecision(COPSLPDPDecision decision, COPSContext context) throws COPSException { + if (!decision.isLocalDecision()) + throw new COPSException ("Local Decision"); + + Vector v = (Vector) _decisions.get(context); + if (decision.isFlagSet()) { + if (v.size() != 0) { + //Only one set of decision flags is allowed + //for each context + throw new COPSException ("Bad Message format, only one set of decision flags is allowed."); + } + } else { + if (v.size() == 0) { + //The flags decision must precede any other + //decision message, since the decision is not + //flags throw exception + throw new COPSException ("Bad Message format, flags decision must precede any other decision object."); + } + } + v.add(decision); + _decisions.put(context,v); + + setMsgLength(); + } + + /** + * Add integrity object + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * Writes data to given socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null) _hdr.writeData(id); + if (_clientHandle != null) _clientHandle.writeData(id); + if (_context != null) _context.writeData(id); + + for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + clientSI.writeData(id); + } + + //Display any local decisions + for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + context.writeData(id); + + for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) { + COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement(); + decision.writeData(id); + } + } + + if (_integrity != null) _integrity.writeData(id); + + } + + /** + * Return Header + * + * @return a COPSHeader + * + */ + public COPSHeader getHeader() { + return _hdr; + } + + /** + * Return client Handle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _clientHandle; + } + + /** + * Return Context + * + * @return a COPSContext + * + */ + public COPSContext getContext() { + return _context; + } + + /** + * Returns true if it has In Interface + * + * @return a boolean + * + */ + public boolean hasInInterface() { + return (_inInterface == null); + } + + /** + * Should check hasInInterface() before calling + * + * @return a COPSInterface + * + */ + public COPSInterface getInInterface() { + return _inInterface; + } + + /** + * Returns true if it has Out interface + * + * @return a boolean + * + */ + public boolean hasOutInterface() { + return (_outInterface == null); + } + + /** + * Should check hasOutInterface() before calling + * + * @return a COPSInterface + * + */ + public COPSInterface getOutInterface() { + return _outInterface; + } + + /** + * Returns a vector if ClientSI objects + * + * @return a Vector + * + */ + public Vector getClientSI() { + return _clientSIs; + } + + /** + * Returns a HashTable of any local decisions + * + * @return a Hashtable + * + */ + public Hashtable getLpdpDecisions() { + return _decisions; + } + + /** + * Returns true if it has Integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity == null); + } + + /** + * Get Integrity. Should check hasIntegrity() becfore calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return _integrity; + } + + /** + * Parses the data and fills COPSReqMsg with its constituents + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + super.parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_HANDLE: { + _clientHandle = new COPSHandle(buf); + _dataStart += _clientHandle.getDataLength(); + } + break; + case COPSObjHeader.COPS_CONTEXT: { + if (_context == null) { + //Message context + _context = new COPSContext(buf); + _dataStart += _context.getDataLength(); + } else { + //lpdp context + _lpdpContext = new COPSContext(buf); + _dataStart += _lpdpContext.getDataLength(); + } + } + break; + case COPSObjHeader.COPS_ININTF: { + if (objHdr.getCType() == 1) { + _inInterface = new COPSIpv4InInterface(buf); + } else { + _inInterface = new COPSIpv6InInterface(buf); + } + _dataStart += _inInterface.getDataLength(); + } + break; + case COPSObjHeader.COPS_OUTINTF: { + if (objHdr.getCType() == 1) { + _outInterface = new COPSIpv4OutInterface(buf); + } else { + _outInterface = new COPSIpv6OutInterface(buf); + } + _dataStart += _outInterface.getDataLength(); + } + break; + case COPSObjHeader.COPS_LPDP_DEC: { + COPSLPDPDecision lpdp = new COPSLPDPDecision(buf); + _dataStart += lpdp.getDataLength(); + addLocalDecision(lpdp, _lpdpContext); + } + break; + case COPSObjHeader.COPS_CSI: { + COPSClientSI csi = new COPSClientSI (buf); + _dataStart += csi.getDataLength(); + _clientSIs.add(csi); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format, unknown object type"); + } + } + } + checkSanity(); + + } + + /** + * Parses the data and fills that follows the header hdr and fills COPSReqMsg + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + short len = 0; + + if (_clientHandle != null) + len += _clientHandle.getDataLength(); + + if (_context != null) + len += _context.getDataLength(); + + for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + len += clientSI.getDataLength(); + } + + //Display any local decisions + for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + len += context.getDataLength(); + + for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) { + COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement(); + len += decision.getDataLength(); + } + } + + if (_integrity != null) { + len += _integrity.getDataLength(); + } + + _hdr.setMsgLength((int) len); + + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_clientHandle != null) + _clientHandle.dump(os); + + if (_context != null) + _context.dump(os); + + for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) { + COPSClientSI clientSI = (COPSClientSI) e.nextElement(); + clientSI.dump(os); + } + + //Display any local decisions + for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) { + + COPSContext context = (COPSContext) e.nextElement(); + Vector v = (Vector) _decisions.get(context); + context.dump(os); + + for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) { + COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement(); + decision.dump(os); + } + } + + if (_integrity != null) { + _integrity.dump(os); + } + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSSyncStateMsg.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSSyncStateMsg.java new file mode 100644 index 0000000..628e413 --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSSyncStateMsg.java @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Sync State Message (RFC 2748 pag. 26 and pag. 29 + * + * The format of the Synchronize State Query message is as follows: + * + * ::= + * [] + * [] + * + * This message indicates that the remote PDP wishes the client (which + * appears in the common header) to re-send its state. If the optional + * Client Handle is present, only the state associated with this handle + * is synchronized. If the PEP does not recognize the requested handle, + * it MUST immediately send a DRQ message to the PDP for the handle that + * was specified in the SSQ message. If no handle is specified in the + * SSQ message, all the active client state MUST be synchronized with + * the PDP. + * + * The client performs state synchronization by re-issuing request + * queries of the specified client-type for the existing state in the + * PEP. When synchronization is complete, the PEP MUST issue a + * synchronize state complete message to the PDP. + * + * ::= + * [] + * [] + * + * The Client Handle object only needs to be included if the corresponding + * Synchronize State Message originally referenced a specific handle. + * + * @version COPSSyncStateMsg.java, v 1.00 2003 + * + */ +public class COPSSyncStateMsg extends COPSMsg { + + /* COPSHeader coming from base class */ + private COPSHandle _clientHandle; + private COPSIntegrity _integrity; + + public COPSSyncStateMsg() { + _clientHandle = null; + _integrity = null; + } + + /** + Parse data and create COPSSyncStateMsg object + */ + protected COPSSyncStateMsg(byte[] data) throws COPSException { + _clientHandle = null; + _integrity = null; + parse(data); + } + + /** + * Checks the sanity of COPS message and throw an + * COPSException when data is bad. + */ + public void checkSanity() throws COPSException { + if (_hdr == null) { + throw new COPSException("Bad message format"); + } + } + + /** + * Add message header + * + * @param hdr a COPSHeader + * + * @throws COPSException + * + */ + public void add (COPSHeader hdr) throws COPSException { + if (hdr == null) + throw new COPSException ("Null Header"); + if ((hdr.getOpCode() != COPSHeader.COPS_OP_SSC) && + (hdr.getOpCode() != COPSHeader.COPS_OP_SSQ)) + throw new COPSException ("Error Header (no COPS_OP_SSX)"); + _hdr = hdr; + setMsgLength(); + } + + /** + * Add client handle to the message + * + * @param handle a COPSHandle + * + * @throws COPSException + * + */ + public void add (COPSHandle handle) throws COPSException { + if (handle == null) + throw new COPSException ("Null Handle"); + + //Message integrity object should be the very last one + //If it is already added + if (_integrity != null) + throw new COPSException ("No null Handle"); + + _clientHandle = handle; + setMsgLength(); + } + + /** + * Add integrity object + * + * @param integrity a COPSIntegrity + * + * @throws COPSException + * + */ + public void add (COPSIntegrity integrity) throws COPSException { + if (integrity == null) + throw new COPSException ("Null Integrity"); + if (!integrity.isMessageIntegrity()) + throw new COPSException ("Error Integrity"); + _integrity = integrity; + setMsgLength(); + } + + /** + * If the optional Client Handle is present, only the state associated + * with this handle is synchronized. If no handle is specified in the + * SSQ message, all the active client state MUST be synchronized with + * the PDP. + * + * @return a boolean + * + */ + public boolean hasClientHandle() { + return (_clientHandle != null); + } + + /** + * Get client Handle + * + * @return a COPSHandle + * + */ + public COPSHandle getClientHandle() { + return _clientHandle; + } + + /** + * Returns true if it has integrity object + * + * @return a boolean + * + */ + public boolean hasIntegrity() { + return (_integrity != null); + } + + /** + * Get Integrity. Should check hasIntegrity() before calling + * + * @return a COPSIntegrity + * + */ + public COPSIntegrity getIntegrity() { + return (_integrity); + } + + /** + * Writes data to given socket + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + // checkSanity(); + if (_hdr != null) _hdr.writeData(id); + if (_clientHandle != null) _clientHandle.writeData(id); + if (_integrity != null) _integrity.writeData(id); + + } + + /** + * Parse data + * + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(byte[] data) throws COPSException { + super.parseHeader(data); + + while (_dataStart < _dataLength) { + byte[] buf = new byte[data.length - _dataStart]; + System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart); + + COPSObjHeader objHdr = new COPSObjHeader (buf); + switch (objHdr.getCNum()) { + case COPSObjHeader.COPS_HANDLE: { + _clientHandle = new COPSHandle(buf); + _dataStart += _clientHandle.getDataLength(); + } + break; + case COPSObjHeader.COPS_MSG_INTEGRITY: { + _integrity = new COPSIntegrity(buf); + _dataStart += _integrity.getDataLength(); + } + break; + default: { + throw new COPSException("Bad Message format, unknown object type"); + } + } + } + checkSanity(); + } + + /** + * Parse data + * + * @param hdr a COPSHeader + * @param data a byte[] + * + * @throws COPSException + * + */ + protected void parse(COPSHeader hdr, byte[] data) throws COPSException { + + if ((hdr.getOpCode() != COPSHeader.COPS_OP_SSC) && + (hdr.getOpCode() != COPSHeader.COPS_OP_SSQ)) + throw new COPSException ("Error Header (no COPS_OP_SSX)"); + + _hdr = hdr; + parse(data); + setMsgLength(); + } + + /** + * Set the message length, base on the set of objects it contains + * + * @throws COPSException + * + */ + protected void setMsgLength() throws COPSException { + short len = 0; + if (_clientHandle != null) len += _clientHandle.getDataLength(); + if (_integrity != null) len += _integrity.getDataLength(); + _hdr.setMsgLength(len); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _hdr.dump(os); + + if (_clientHandle != null) + _clientHandle.dump(os); + + if (_integrity != null) { + _integrity.dump(os); + } + } +} + + + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSTimer.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSTimer.java new file mode 100644 index 0000000..5fe1a4f --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSTimer.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; + +/** + * COPS Timer Object + * + * @version COPSTimer.java, v 1.00 2003 + * + */ +public class COPSTimer extends COPSObjBase { + + protected COPSObjHeader _objHdr; + private short _reserved; + private short _timerValue; + + /** + * Returns size in number of octects, including header + * + * @return a short + * + */ + public short getDataLength() { + //Add the size of the header also + return (_objHdr.getDataLength()); + } + + /** + * Method getTimerVal + * + * @return a short + * + */ + public short getTimerVal() { + return _timerValue; + }; + + /** + * Method isTimer + * + * @return a boolean + * + */ + public boolean isTimer() { + return true; + }; + + /** + * Method isKATimer + * + * @return a boolean + * + */ + public boolean isKATimer() { + return false; + }; + + /** + * Method isAcctTimer + * + * @return a boolean + * + */ + public boolean isAcctTimer() { + return false; + }; + + /** + * Write data to given socket in Network byte order + * + * @param id a Socket + * + * @throws IOException + * + */ + public void writeData(Socket id) throws IOException { + _objHdr.writeData(id); + + byte[] buf = new byte[4]; + + buf[0] = (byte) (_reserved >> 8); + buf[1] = (byte) _reserved; + buf[2] = (byte) (_timerValue >> 8); + buf[3] = (byte) _timerValue; + COPSUtil.writeData(id, buf, 4); + } + + protected COPSTimer(short timeVal) { + _objHdr = new COPSObjHeader(); + //Time range is 1 - 65535 seconds + _timerValue = timeVal; + // _objHdr.setDataLength(sizeof(u_int32_t)); + _objHdr.setDataLength((short) 4); + } + + /** + * Receive data that is in netwrok byte order and fill in the obj. + */ + protected COPSTimer(byte[] dataPtr) { + _objHdr = new COPSObjHeader(); + _objHdr.parse(dataPtr); + // _objHdr.checkDataLength(); + + _reserved |= ((short) dataPtr[4]) << 8; + _reserved |= ((short) dataPtr[5]) & 0xFF; + _timerValue |= ((short) dataPtr[6]) << 8; + _timerValue |= ((short) dataPtr[7]) & 0xFF; + + // _objHdr.setDataLength(sizeof(u_int32_t)); + _objHdr.setDataLength((short) 4); + } + + /** + * Write an object textual description in the output stream + * + * @param os an OutputStream + * + * @throws IOException + * + */ + public void dump(OutputStream os) throws IOException { + _objHdr.dump(os); + os.write(new String("Timer val: " + _timerValue + "\n").getBytes()); + } + +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSTransceiver.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSTransceiver.java new file mode 100644 index 0000000..56471de --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSTransceiver.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.net.Socket; + +// import org.umu.cops.common.COPSDebug; + +/** + * COPS Transceiver + * + * @version COPSTransceiver.java, v 1.00 2003 + * + */ +public class COPSTransceiver { + + /** + * Method sendMsg + * + * @param msg a COPSMsg + * @param fd a Socket + * + * @throws IOException + * @throws COPSException + * + */ + static public void sendMsg(COPSMsg msg, Socket fd) throws IOException, COPSException { + // COPSDebug.out("COPSTransceiver", "sendMsg ******************************** START" ); + + msg.checkSanity(); + msg.writeData(fd); + + // COPSDebug.out("COPSTransceiver", "sendMsg ******************************** END" ); + } + + /** + * Method receiveMsg + * + * @param fd a Socket + * + * @return a COPSMsg + * + * @throws IOException + * @throws COPSException + * + */ + static public COPSMsg receiveMsg (Socket fd) throws IOException, COPSException { + int nread = 0; + byte[] hBuf = new byte[8]; + + // COPSDebug.out("COPSTransceiver", "receiveMsg ******************************** START" ); + + nread = COPSUtil.readData(fd, hBuf, 8); + + if (nread == 0) { + throw new COPSException("Error reading connection"); + } + + if (nread != 8) { + throw new COPSException("Bad COPS message"); + } + + COPSHeader hdr = new COPSHeader(hBuf); + int dataLen = hdr.getMsgLength() - hdr.getHdrLength(); + // COPSDebug.out("COPSTransceiver", "COPS Msg length :[" + dataLen + "]\n" ); + byte[] buf = new byte[dataLen + 1]; + nread = 0; + + nread = COPSUtil.readData(fd, buf, dataLen); + buf[dataLen] = (byte) '\0'; + // COPSDebug.out("COPSTransceiver", "Data read length:[" + nread + "]\n"); + + if (nread != dataLen) { + throw new COPSException("Bad COPS message"); + } + + COPSMsgParser prser = new COPSMsgParser(); + COPSMsg msg = prser.parse(hdr, buf); + + // COPSDebug.out("COPSTransceiver", "Message received"); + + // COPSDebug.out("COPSTransceiver", "receiveMsg ******************************** END" ); + return msg; + } +} + diff --git a/packetcable-driver/src/main/java/org/umu/cops/stack/COPSUtil.java b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSUtil.java new file mode 100644 index 0000000..072da7b --- /dev/null +++ b/packetcable-driver/src/main/java/org/umu/cops/stack/COPSUtil.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2003 University of Murcia. All rights reserved. + * -------------------------------------------------------------- + * For more information, please see . + */ + +package org.umu.cops.stack; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Date; + +/** + * COPS Utils + * + * @version COPSUtil.java, v 2.00 2004 + * + */ +public class COPSUtil { + + /** + * Method writeData + * + * @param id a Socket + * @param data a byte[] + * @param len an int + * + * @throws IOException + * + */ + static void writeData(Socket id, byte[] data, int len) throws IOException { + OutputStream output; + output = id.getOutputStream(); + + output.write(data,0,len); + } + + /** + * Reads nchar from a given sockets, blocks on read untill nchar are read of conenction has error + * bRead returns the bytes read + * + * @param connId a Socket + * @param dataRead a byte[] + * @param nchar an int + * + * @return an int + * + * @throws IOException + * + */ + static int readData(Socket connId, byte[] dataRead, int nchar) throws IOException { + InputStream input; + input = connId.getInputStream(); + + int nread = 0; + int startTime = (int) (new Date().getTime()); + do { + if (input.available() != 0) { + nread += input.read(dataRead,nread,nchar-nread); + startTime = (int) (new Date().getTime()); + } else { + int nowTime = (int) (new Date().getTime()); + if ((int)(nowTime - startTime) > 2000) + break; + } + } while (nread != nchar); + + return nread; + } +} + diff --git a/packetcable-driver/src/main/resources/pcmm.properties b/packetcable-driver/src/main/resources/pcmm.properties new file mode 100644 index 0000000..5f696df --- /dev/null +++ b/packetcable-driver/src/main/resources/pcmm.properties @@ -0,0 +1,15 @@ +#---------------------------------------------------------------------------------- +# This file contains the common properties of the PCMM +#---------------------------------------------------------------------------------- +#Port used by the PCMM +pcmm.port=3918 +#Pool size, determining the number of connections that could be established with CMTSs +pcmm.ps.pool.size=32 +#Default keep-alive timer value (secs) +pcmm.keep.alive.timer = 30 +#Default accounting timer value (secs) +pcmm.accounting.timer = 0; +#default mask +pcmm.default.mask=0.0.0.0 +#timeout for the connection in ms +pcmm.default.timeout=-1 \ No newline at end of file diff --git a/packetcable-driver/src/test/java/org/pcmm/test/BestEffortServiceTest.java b/packetcable-driver/src/test/java/org/pcmm/test/BestEffortServiceTest.java new file mode 100644 index 0000000..defde2e --- /dev/null +++ b/packetcable-driver/src/test/java/org/pcmm/test/BestEffortServiceTest.java @@ -0,0 +1,42 @@ +package org.pcmm.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.pcmm.gates.impl.BestEffortService; + +public class BestEffortServiceTest { + + private BestEffortService be; + + @Before + public void init() { + be = new BestEffortService((byte) 7); + be.getAuthorizedEnvelop().setMinimumReservedTrafficRate(192); + be.getCommittedEnvelop().setRequiredAttributeMask(938); + be.getReservedEnvelop().setTrafficPriority((byte) 5); + } + + @Test + public void testGetAsBinaryArray() { + assertTrue(be.getAsBinaryArray().length == 116); + } + + @Test + public void testBestEffortServiceByteArray() { + assertTrue(new BestEffortService(be.getAsBinaryArray()) + .getAuthorizedEnvelop().getMinimumReservedTrafficRate() == 192); + assertTrue(new BestEffortService(be.getAsBinaryArray()) + .getReservedEnvelop().getTrafficPriority() == 5); + assertTrue(new BestEffortService(be.getAsBinaryArray()) + .getCommittedEnvelop().getRequiredAttributeMask() == 938); + + } + + @Test + public void testGetEnvelop() { + assertTrue(be.getEnvelop() == 7); + } + +} diff --git a/packetcable-driver/src/test/java/org/pcmm/test/Main.java b/packetcable-driver/src/test/java/org/pcmm/test/Main.java new file mode 100644 index 0000000..ad1ea5e --- /dev/null +++ b/packetcable-driver/src/test/java/org/pcmm/test/Main.java @@ -0,0 +1,49 @@ +/** + * + */ +package org.pcmm.test; + +import org.pcmm.rcd.ICMTS; +import org.pcmm.rcd.IPCMMPolicyServer; +import org.pcmm.rcd.IPCMMPolicyServer.IPSCMTSClient; +import org.pcmm.rcd.impl.CMTS; +import org.pcmm.rcd.impl.PCMMPolicyServer; + +/** + * + */ +public class Main { + + /** + * @param args + */ + public static void main(String[] args) { + ICMTS icmts = new CMTS(); + icmts.startServer(); + IPCMMPolicyServer ps = new PCMMPolicyServer(); + IPSCMTSClient client = ps.requestCMTSConnection("localhost"); + client.gateSet(); + // IWorkerPool pool = new WorkerPool(2); + // IWorker worker = new Worker(new Callable() { + // @Override + // public String call() throws Exception { + // System.out + // .println("Main.main(...).new Callable() {...}.call()"); + // return null; + // } + // }); + // IWorker worker2 = new Worker(new Callable() { + // @Override + // public String call() throws Exception { + // System.out + // .println("|||||||Main.main(...).new Callable() {...}.call()||||||||||||"); + // return null; + // } + // }); + // pool.schedule(worker2, 2000); + // pool.schedule(worker, 500); + // pool.recycle(); + + + } +} diff --git a/packetcable-driver/src/test/java/org/pcmm/test/PCErrorTest.java b/packetcable-driver/src/test/java/org/pcmm/test/PCErrorTest.java new file mode 100644 index 0000000..d6f129a --- /dev/null +++ b/packetcable-driver/src/test/java/org/pcmm/test/PCErrorTest.java @@ -0,0 +1,29 @@ +package org.pcmm.test; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.pcmm.gates.IPCMMError; +import org.pcmm.gates.impl.PCMMError; + +public class PCErrorTest { + + IPCMMError error; + + @Before + public void init() { + error = new PCMMError(); + error.setErrorCode((short) 1); + } + + @Test + public void testGetDescription() { + for (IPCMMError.Description d : IPCMMError.Description.values()) { + error.setErrorCode(d.getCode()); + Assert.assertNotNull(error.getDescription()); + System.out.println(error.getDescription()); + } + + } + +} diff --git a/packetcable-driver/src/test/java/org/pcmm/test/PCMMGateReqTest.java b/packetcable-driver/src/test/java/org/pcmm/test/PCMMGateReqTest.java new file mode 100644 index 0000000..bfd622c --- /dev/null +++ b/packetcable-driver/src/test/java/org/pcmm/test/PCMMGateReqTest.java @@ -0,0 +1,40 @@ +/** + * + */ +package org.pcmm.test; + +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.pcmm.gates.impl.PCMMGateReq; +import org.pcmm.utils.PCMMUtils; + +/** + * @author RH030971 + * + */ +public class PCMMGateReqTest { + + /** + * Test method for + * {@link org.pcmm.gates.impl.PCMMGateReq#PCMMGateReq(byte[])}. + */ + @Test + public void testPCMMGateReqByteArray() { +/* + new PCMMGateReq( + PCMMUtils + .ReadBinaryDump("traces/COPSReportClientSI09871088-5329-44ff-b1db-0ea3a544de1e.bin")); + +*/ + } + + /** + * Test method for {@link org.pcmm.gates.impl.PCMMGateReq#getData()}. + */ + @Test + public void testGetData() { + // fail("Not yet implemented"); + } + +} diff --git a/packetcable-driver/src/test/java/org/pcmm/test/PCMMResourceSetTest.java b/packetcable-driver/src/test/java/org/pcmm/test/PCMMResourceSetTest.java new file mode 100644 index 0000000..5f17e59 --- /dev/null +++ b/packetcable-driver/src/test/java/org/pcmm/test/PCMMResourceSetTest.java @@ -0,0 +1,39 @@ +package org.pcmm.test; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.pcmm.objects.PCMMIDHolder; +import org.pcmm.objects.PCMMResourceSet; +import org.pcmm.objects.PCMMResourcesMapper; + +public class PCMMResourceSetTest { + + + @Test + public void testGetMappedResources() { + + int flowID=100; + short trId=(short)123; + //typical use of PCMMresourceSet to add a new mapping + PCMMResourceSet.getInstance().mapResources( /* flow ID */flowID, + new PCMMResourcesMapper(/* transactionID */(short)trId, + /* PCMMIDHolder */new PCMMIDHolder(/* flowID */flowID, /* gateID */0, /* transactionID */trId))); + + // if we want to retrieve or update mapped data + PCMMIDHolder holder = (PCMMIDHolder) PCMMResourceSet.getInstance().getMappedResources(/* flow ID */flowID).getValue(); + short transID=(short) PCMMResourceSet.getInstance().getMappedResources(/* flow ID */flowID).getKey(); + + assertTrue(holder.getFlowID()==flowID); + assertTrue(holder.getTransactionID()==trId); + assertTrue(transID==trId); + //update gate ID + holder.setGateID(/*gate ID*/ 1234568); + + assertTrue(((PCMMIDHolder) PCMMResourceSet.getInstance().getMappedResources(/* flow ID */flowID).getValue()).getGateID()==1234568); + + + + } + +} diff --git a/packetcable-driver/src/test/java/org/pcmm/test/PCMMWorkflowTest.java b/packetcable-driver/src/test/java/org/pcmm/test/PCMMWorkflowTest.java new file mode 100644 index 0000000..52d77d2 --- /dev/null +++ b/packetcable-driver/src/test/java/org/pcmm/test/PCMMWorkflowTest.java @@ -0,0 +1,99 @@ +package org.pcmm.test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.pcmm.rcd.ICMTS; +import org.pcmm.rcd.IPCMMPolicyServer; +import org.pcmm.rcd.IPCMMPolicyServer.IPSCMTSClient; +import org.pcmm.rcd.impl.CMTS; +import org.pcmm.rcd.impl.PCMMPolicyServer; + +public class PCMMWorkflowTest { + + /** + * CMTS emulator, when testing with a real CMTS this should be set to null + * and shoudln't be started + */ + private static ICMTS cmts; + /** + * CMTS host address, when testing with a real CMTS this should be CMTS + * address + */ + private static InetAddress host; + + private static IPCMMPolicyServer server; + private static IPSCMTSClient client; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + // comment this when using real CMTS + // ################################### + cmts = new CMTS(); + cmts.startServer(); + // ################################### + + server = new PCMMPolicyServer(); + try { + // this should be set to the cmts host ex : + // InetAddress.getByName("10.10.10.10") or + // InetAddress.getByName("my-cmts-host-name") + host = InetAddress.getLocalHost(); + assertNotNull(host); + } catch (UnknownHostException uhe) { + fail("could not get host address "); + } + setupConnection(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + tearDown(); + if (cmts != null) + cmts.stopServer(); + } + + public static void setupConnection() { + client = server.requestCMTSConnection(host); + assertNotNull(client); + } + + public static void tearDown() throws Exception { + assertNotNull(client); + assertTrue("Client disconnection failed", client.disconnect()); + } + + + //@Test + public void testGateSet() { + assertNotNull(client); + assertTrue("Gate-Set failed", client.gateSet()); + } + + //@Test + public void testGateDelete() { + assertNotNull(client); + assertTrue("Gate-Delete failed", client.gateDelete()); + + } + + //@Test + public void testGateInfo() { + assertNotNull(client); + assertTrue("Gate-Info failed", client.gateInfo()); + } + + //@Test + public void testGateSynchronize() { + assertNotNull(client); + assertTrue("Gate-Synchronize failed", client.gateSynchronize()); + } + +} diff --git a/packetcable-driver/src/test/java/org/pcmm/test/README.md b/packetcable-driver/src/test/java/org/pcmm/test/README.md new file mode 100644 index 0000000..f32f06a --- /dev/null +++ b/packetcable-driver/src/test/java/org/pcmm/test/README.md @@ -0,0 +1,2 @@ +This package contains the test set for the PCMM driver, +To test the whole workflow use the junit based test : PCMMWorkflowTest.java \ No newline at end of file diff --git a/pom.xml b/pom.xml index 18b56b5..8e989ac 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ pom + packetcable-driver packetcable-model packetcable-consumer packetcable-provider