Expanded CMTS emulator to respond properly to gate add requests.
[packetcable.git] / packetcable-driver / src / main / java / org / pcmm / rcd / impl / CmtsPepReqStateMan.java
1 /*
2  * (c) 2015 Cable Television Laboratories, Inc.  All rights reserved.
3  */
4
5 package org.pcmm.rcd.impl;
6
7 import org.pcmm.gates.IGateSpec.Direction;
8 import org.pcmm.gates.IPCMMError;
9 import org.pcmm.gates.impl.GateID;
10 import org.pcmm.gates.impl.PCMMError;
11 import org.pcmm.gates.impl.PCMMGateReq;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.umu.cops.prpep.COPSPepException;
15 import org.umu.cops.prpep.COPSPepMsgSender;
16 import org.umu.cops.prpep.COPSPepReqStateMan;
17 import org.umu.cops.stack.*;
18 import org.umu.cops.stack.COPSDecision.DecisionFlag;
19 import org.umu.cops.stack.COPSObjHeader.CNum;
20 import org.umu.cops.stack.COPSObjHeader.CType;
21 import org.umu.cops.stack.COPSReportType.ReportType;
22
23 import java.io.IOException;
24 import java.net.Socket;
25 import java.util.*;
26
27 /**
28  * PEP State manager implementation for use in a CMTS.
29  */
30 public class CmtsPepReqStateMan extends COPSPepReqStateMan {
31
32     private final static Logger logger = LoggerFactory.getLogger(CmtsPepReqStateMan.class);
33
34     /**
35      * The configured gates
36      */
37     private final Map<Direction, Set<String>> gateConfig;
38
39     /**
40      * The connected CMTSs and whether or not they are up
41      */
42     private final Map<String, Boolean> cmStatus;
43
44     /**
45      * Contains the gates that have been set where the key is the gate name and the value is a Set of subIds
46      * that are using this gate
47      */
48     private final Map<String, Set<String>> gatesSetMap;
49
50     /**
51      * Create a State Request Manager
52      *
53      * @param clientType - the client type for this connection
54      * @param clientHandle - the client-handle for this connection
55      * @param process - the data processor
56      * @param socket - the socket connection
57      * @param gateConfig - the configured service class names (gates)
58      */
59     public CmtsPepReqStateMan(final short clientType, final COPSHandle clientHandle, final CmtsDataProcessor process,
60                               final Socket socket, final Map<Direction, Set<String>> gateConfig,
61                               final Map<String, Boolean> cmStatus) {
62         super(clientType, clientHandle, process, socket, new COPSPepMsgSender(clientType, clientHandle, socket));
63         this.gateConfig = Collections.unmodifiableMap(gateConfig);
64         this.cmStatus = Collections.unmodifiableMap(cmStatus);
65
66         this.gatesSetMap = new HashMap<>();
67         for (final Set<String> gateIdSet: gateConfig.values()) {
68             for (final String gateId : gateIdSet) {
69                 gatesSetMap.put(gateId, new HashSet<String>());
70             }
71         }
72     }
73
74     @Override
75     protected void processDecision(final COPSDecisionMsg dMsg) throws COPSException {
76         logger.info("Processing decision message - " + dMsg);
77         final Map<COPSContext, Set<COPSDecision>> decisions = dMsg.getDecisions();
78
79         final Map<String, String> removeDecs = new HashMap<>();
80         final Map<String, String> installDecs = new HashMap<>();
81
82         for (final Set<COPSDecision> copsDecisions: decisions.values()) {
83             final COPSDecision cmddecision = copsDecisions.iterator().next();
84             switch (cmddecision.getCommand()) {
85                 case INSTALL:
86                     for (final COPSDecision decision : copsDecisions) {
87                         if (decision.getFlag().equals(DecisionFlag.REQERROR)) {
88                             logger.info("processing decision");
89                             // This is assuming a gate set right or wrong
90                             if (dMsg.getDecisions().size() == 1 && dMsg.getDecSI() != null) {
91                                 final PCMMGateReq gateReq = new PCMMGateReq(dMsg.getDecSI().getData().getData());
92                                 if (gateReq.getGateSpec() != null) {
93                                     processGateReq(gateReq, _socket);
94                                 }
95                             }
96                         }
97                     }
98                     break;
99                 case REMOVE:
100                     for (final COPSDecision decision : copsDecisions) {
101                         // TODO - implement gate delete
102                     }
103                     break;
104             }
105
106         }
107
108         //** Apply decisions to the configuration
109         // TODO - why is this collection never getting populated???
110         final Map<String, String> errorDecs = new HashMap<>();
111         _process.setDecisions(this, removeDecs, installDecs, errorDecs);
112         _status = Status.ST_DECS;
113
114
115         if (_process.isFailReport(this)) {
116             // COPSDebug.out(getClass().getName(),"Sending FAIL Report\n");
117             _sender.sendFailReport(_process.getReportData(this));
118         } else {
119             // COPSDebug.out(getClass().getName(),"Sending SUCCESS Report\n");
120             _sender.sendSuccessReport(_process.getReportData(this));
121         }
122         _status = Status.ST_REPORT;
123
124         if (!_syncState) {
125             _sender.sendSyncComplete();
126             _syncState = true;
127             _status = Status.ST_SYNCALL;
128         }
129     }
130
131     private void processGateReq(final PCMMGateReq gateReq, final Socket socket) throws COPSException {
132         // TODO - Check and/or Set state here
133         // Gate ADD gateReq.getTrafficProfile() != null
134         // Gate REMOVE gateReq.getTrafficProfile() == null
135         final String subId = gateReq.getSubscriberID().getSourceIPAddress().getHostAddress();
136
137         // Get direction here
138         final Direction gateDir = gateReq.getGateSpec().getDirection();
139         final Set<String> gateNames = gateConfig.get(gateDir);
140         final String gateName = gateReq.getTrafficProfile().getData().str();
141
142         IPCMMError error = new PCMMError();
143         if (subId == null || gateDir == null || gateNames == null || gateName == null) {
144             // Missing required object
145             error.setErrorCode((short)3);
146         } else if (!cmStatus.keySet().contains(subId)
147                 || (cmStatus.keySet().contains(subId) && !cmStatus.get(subId))) {
148             // Invalid Object
149             error.setErrorCode((short)13);
150         } else if (!gateNames.contains(gateName.trim())) {
151             error.setErrorCode((short)11);
152         } else {
153             error = null;
154             gatesSetMap.get(gateName.trim()).add(subId);
155         }
156         gateReq.setError(error);
157
158         logger.info("Processing gate request [" + gateName + "] with direction [" + gateDir + ']');
159
160         // Get gate name
161
162         // Set response
163         final List<Byte> data = new ArrayList<>();
164         for (final byte val : gateReq.getTransactionID().getAsBinaryArray())
165             data.add(val);
166         for (final byte val : gateReq.getAMID().getAsBinaryArray())
167             data.add(val);
168         for (final byte val : gateReq.getSubscriberID().getAsBinaryArray())
169             data.add(val);
170         if (error != null) for (final byte val : gateReq.getError().getAsBinaryArray())
171             data.add(val);
172
173         // Assign a gate ID
174         final GateID gateID = new GateID();
175         gateID.setGateID(UUID.randomUUID().hashCode());
176         for (final byte val : gateID.getAsBinaryArray())
177             data.add(val);
178
179
180         final byte[] csiArr = new byte[data.size()];
181         for (int i = 0; i < data.size(); i++) {
182             csiArr[i] = data.get(i);
183         }
184         final COPSClientSI si = new COPSClientSI(CNum.CSI, CType.DEF, new COPSData(csiArr, 0, csiArr.length));
185
186         final ReportType reportType;
187         if (gateReq.getError() == null) reportType = ReportType.SUCCESS; else reportType = ReportType.FAILURE;
188
189         logger.info("Returning " + reportType + " for gate request [" + gateName + "] direction [" + gateDir
190                 + "] for host - " + subId);
191         final COPSReportMsg reportMsg = new COPSReportMsg(_clientType, getClientHandle(),
192                     new COPSReportType(reportType), si, null);
193         try {
194             reportMsg.writeData(socket);
195         } catch (IOException e) {
196             throw new COPSPepException("Error writing gate set SUCCESS Report", e);
197         }
198     }
199
200 }