[SEBA-593] Splitting aaa app in implementation and api bundles
Change-Id: Ib81650be0695258bdd1f4cd6131f2206760e0da6
diff --git a/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java b/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java
new file mode 100755
index 0000000..e2bce35
--- /dev/null
+++ b/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.aaa.impl;
+
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.RADIUS;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketService;
+import org.opencord.aaa.AaaConfig;
+import org.opencord.aaa.RadiusCommunicator;
+import org.slf4j.Logger;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/**
+ * Handles Socket based communication with the RADIUS server.
+ */
+public class SocketBasedRadiusCommunicator implements RadiusCommunicator {
+
+ // for verbose output
+ private final Logger log = getLogger(getClass());
+
+ // our unique identifier
+ private ApplicationId appId;
+
+ // to receive Packet-in events that we'll respond to
+ PacketService packetService;
+
+ // Socket used for UDP communications with RADIUS server
+ private DatagramSocket radiusSocket;
+
+ private String radiusHost;
+
+ // Parsed RADIUS server addresses
+ protected InetAddress radiusIpAddress;
+
+ // RADIUS server TCP port number
+ protected short radiusServerPort;
+
+ // Executor for RADIUS communication thread
+ private ExecutorService executor;
+
+ AaaManager aaaManager;
+
+ SocketBasedRadiusCommunicator(ApplicationId appId, PacketService pktService,
+ AaaManager aaaManager) {
+ this.appId = appId;
+ this.packetService = pktService;
+ this.aaaManager = aaaManager;
+ }
+
+ @Override
+ public void initializeLocalState(AaaConfig newCfg) {
+ if (newCfg.radiusIp() != null) {
+ radiusIpAddress = newCfg.radiusIp();
+ }
+ radiusServerPort = newCfg.radiusServerUdpPort();
+ radiusHost = newCfg.radiusHostName();
+
+ try {
+ radiusSocket = new DatagramSocket(null);
+ radiusSocket.setReuseAddress(true);
+ radiusSocket.bind(new InetSocketAddress(radiusServerPort));
+ } catch (Exception ex) {
+ log.error("Can't open RADIUS socket", ex);
+ }
+
+ log.info("Remote RADIUS Server: {}:{}", radiusIpAddress, radiusServerPort);
+
+ executor = Executors.newSingleThreadExecutor(
+ new ThreadFactoryBuilder()
+ .setNameFormat("AAA-radius-%d").build());
+ executor.execute(radiusListener);
+ }
+
+ @Override
+ public void clearLocalState() {
+ radiusSocket.close();
+ executor.shutdownNow();
+ }
+
+ @Override
+ public void deactivate() {
+ clearLocalState();
+ }
+
+ @Override
+ public void requestIntercepts() {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
+ packetService.requestPackets(selector.build(), CONTROL, appId);
+ }
+
+ @Override
+ public void withdrawIntercepts() {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
+ packetService.cancelPackets(selector.build(), CONTROL, appId);
+ }
+
+ @Override
+ public void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
+ try {
+ final byte[] data = radiusPacket.serialize();
+ final DatagramSocket socket = radiusSocket;
+
+ try {
+ InetAddress address;
+ if (radiusHost != null) {
+ address = InetAddress.getByName(radiusHost);
+ } else {
+ address = radiusIpAddress;
+ }
+ DatagramPacket packet =
+ new DatagramPacket(data, data.length, address, radiusServerPort);
+ if (log.isTraceEnabled()) {
+ log.trace("Sending packet {} to Radius Server {}:{} using socket",
+ radiusPacket, address, radiusServerPort);
+ }
+ socket.send(packet);
+ } catch (UnknownHostException uhe) {
+ log.warn("Unable to resolve host {}", radiusHost);
+ }
+ } catch (IOException e) {
+ log.info("Cannot send packet to RADIUS server", e);
+ }
+ }
+
+ @Override
+ public void handlePacketFromServer(PacketContext context) {
+ InboundPacket pkt = context.inPacket();
+ Ethernet ethPkt = pkt.parsed();
+ if (log.isTraceEnabled() && ethPkt.getEtherType() != Ethernet.TYPE_LLDP
+ && ethPkt.getEtherType() != Ethernet.TYPE_BSN) {
+ log.trace("Skipping Ethernet packet type {}",
+ EthType.EtherType.lookup(ethPkt.getEtherType()));
+ }
+ }
+
+ class RadiusListener implements Runnable {
+
+ @Override
+ public void run() {
+ boolean done = false;
+ int packetNumber = 1;
+
+ log.info("UDP listener thread starting up");
+ RADIUS inboundRadiusPacket;
+ while (!done) {
+ try {
+ byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
+ DatagramPacket inboundBasePacket =
+ new DatagramPacket(packetBuffer, packetBuffer.length);
+ DatagramSocket socket = radiusSocket;
+ socket.receive(inboundBasePacket);
+ log.debug("Packet #{} received", packetNumber++);
+ try {
+ inboundRadiusPacket =
+ RADIUS.deserializer()
+ .deserialize(inboundBasePacket.getData(),
+ 0,
+ inboundBasePacket.getLength());
+ aaaManager.handleRadiusPacket(inboundRadiusPacket);
+ } catch (DeserializationException dex) {
+ log.error("Cannot deserialize packet", dex);
+ } catch (StateMachineException sme) {
+ log.error("Illegal state machine operation", sme);
+ }
+
+ } catch (IOException e) {
+ log.info("Socket was closed, exiting listener thread");
+ done = true;
+ }
+ }
+ }
+ }
+
+ RadiusListener radiusListener = new RadiusListener();
+}