summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPServer.java93
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPSession.java40
2 files changed, 127 insertions, 6 deletions
diff --git a/src/main/java/com/lumaserv/bgp/BGPServer.java b/src/main/java/com/lumaserv/bgp/BGPServer.java
index 80ec7ff..e95caea 100644
--- a/src/main/java/com/lumaserv/bgp/BGPServer.java
+++ b/src/main/java/com/lumaserv/bgp/BGPServer.java
@@ -1,6 +1,7 @@
package com.lumaserv.bgp;
import com.lumaserv.bgp.protocol.BGPPacket;
+import com.lumaserv.bgp.protocol.message.BGPNotification;
import com.lumaserv.bgp.protocol.message.BGPOpen;
import lombok.Getter;
@@ -39,6 +40,77 @@ public class BGPServer implements Runnable {
return true;
}
+ public boolean hasCollided(BGPSession session, BGPOpen msg) {
+ for (BGPSession otherSession : sessions) {
+ BGPFsm fsm = otherSession.getFsm();
+ BGPFsm.State state = fsm.getCurrentState();
+
+ // May examine OPEN_SENT
+ if (state == fsm.OPEN_SENT
+ && otherSession.getConfiguration() == null)
+ continue;
+
+ // Cannot detect collision
+ if (state == fsm.IDLE
+ || state == fsm.CONNECT
+ || state == fsm.ACTIVE)
+ continue;
+
+ // Detect collision
+ if (session.getInetAddress() != otherSession.getLocalAddress()
+ || session.getLocalAddress() != otherSession.getInetAddress())
+ continue;
+
+ // Collision!
+ if (state == fsm.ESTABLISHED) {
+ // Close new connection
+ sessions.remove(session);
+ return true;
+ }
+
+ byte[] remoteIdentifier;
+ byte[] localIdentifier = session.getConfiguration()
+ .getLocalIdentifier();
+
+ if (state == fsm.OPEN_SENT) {
+ remoteIdentifier = otherSession.getConfiguration()
+ .getRemoteIdentifier();
+ } else { // state == BGPFsm.OPEN_CONFIRM
+ remoteIdentifier = otherSession.getRemoteIdentifier();
+ }
+
+ boolean isLocalIdLess = false;
+
+ // Compare integer stored in network byte order
+ for (int i=0; i < 4; i++) {
+ if (localIdentifier[i] < remoteIdentifier[i]) {
+ isLocalIdLess = true;
+ break;
+ }
+ }
+
+ if (isLocalIdLess) {
+ // Close existing connection
+ BGPNotification notification = new BGPNotification()
+ .setMajorErrorCode(BGPNotification.Error.CEASE.getCode());
+ try {
+ otherSession.sendNotification(notification);
+ } catch(IOException ex) {
+ }
+ sessions.remove(otherSession);
+ otherSession.dropConnection();
+ // Accept new connection
+ return false;
+ } else {
+ // Close new connection
+ sessions.remove(session);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public void run() {
while (true) {
try {
@@ -57,7 +129,7 @@ public class BGPServer implements Runnable {
}
BGPFsm fsm = new BGPFsm();
- BGPSession session = new BGPSession(socket, config, fsm);
+ BGPSession session = new BGPSession(this, socket, config, fsm);
fsm.setSession(session);
sessions.add(session);
System.out.println("automaticStartPassive");
@@ -66,6 +138,8 @@ public class BGPServer implements Runnable {
// System.out.println("tcpConnectionConfirmed in " + fsm.getCurrentState());
// fsm.getCurrentState().tcpConnectionConfirmed();
} catch (IOException ex) {
+ if (serverSocket.isClosed())
+ break;
ex.printStackTrace();
}
}
@@ -76,9 +150,16 @@ public class BGPServer implements Runnable {
}
public boolean connect(BGPSessionConfiguration config, String host, int port) throws IOException {
+ for (BGPSession session : sessions) {
+ if (session.getConfiguration().equals(config)) {
+ // Already connected
+ return false;
+ }
+ }
+
try {
BGPFsm fsm = new BGPFsm();
- BGPSession session = new BGPSession(config, fsm, host, port);
+ BGPSession session = new BGPSession(this, config, fsm, host, port);
fsm.setSession(session);
sessions.add(session);
fsm.getCurrentState().automaticStart();
@@ -93,5 +174,13 @@ public class BGPServer implements Runnable {
for(BGPSession session : sessions) {
session.automaticStop();
}
+ sessions.clear();
+ if (serverSocket != null) {
+ try {
+ serverSocket.close();
+ } catch(IOException ex) {
+ ex.printStackTrace();
+ }
+ }
}
}
diff --git a/src/main/java/com/lumaserv/bgp/BGPSession.java b/src/main/java/com/lumaserv/bgp/BGPSession.java
index bb38ebf..e785e3b 100644
--- a/src/main/java/com/lumaserv/bgp/BGPSession.java
+++ b/src/main/java/com/lumaserv/bgp/BGPSession.java
@@ -11,6 +11,7 @@ import lombok.Getter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
@@ -18,6 +19,8 @@ import java.net.SocketException;
public class BGPSession implements Runnable {
@Getter
+ final BGPServer server;
+ @Getter
final BGPSessionConfiguration configuration;
final String host;
final int port;
@@ -27,13 +30,17 @@ public class BGPSession implements Runnable {
@Getter
boolean closed;
boolean outgoing;
+ @Getter
BGPFsm fsm;
Thread thread;
boolean isAdvAS4Capability;
@Getter
boolean isAS4Capability;
+ @Getter
+ byte[] remoteIdentifier;
- public BGPSession(Socket socket, BGPSessionConfiguration configuration, BGPFsm fsm) throws IOException {
+ public BGPSession(BGPServer server, Socket socket, BGPSessionConfiguration configuration, BGPFsm fsm) throws IOException {
+ this.server = server;
this.configuration = configuration;
this.socket = socket;
this.inputStream = socket.getInputStream();
@@ -43,13 +50,26 @@ public class BGPSession implements Runnable {
this.port = -1;
}
- public BGPSession(BGPSessionConfiguration configuration, BGPFsm fsm, String host, int port) throws IOException {
+ public BGPSession(BGPServer server, BGPSessionConfiguration configuration, BGPFsm fsm, String host, int port) throws IOException {
+ this.server = server;
this.configuration = configuration;
this.fsm = fsm;
this.host = host;
this.port = port;
}
+ public InetAddress getInetAddress() {
+ return socket.getInetAddress();
+ }
+
+ public InetAddress getLocalAddress() {
+ return socket.getLocalAddress();
+ }
+
+ protected void finalize() throws Throwable {
+ System.out.println("Finalize BGPSession");
+ }
+
public void automaticStop() {
fsm.getCurrentState().automaticStop();
}
@@ -78,8 +98,20 @@ public class BGPSession implements Runnable {
break;
case OPEN:
BGPOpen open = new BGPOpen(packet.getMessage());
- isAS4Capability = isAdvAS4Capability && open.getAS4Capability().isPresent();
- fsm.getCurrentState().openMsg(open);
+ if (server.hasCollided(this, open)) {
+ BGPNotification notification = new BGPNotification()
+ .setMajorErrorCode(BGPNotification.Error.CEASE.getCode());
+ try {
+ sendNotification(notification);
+ } catch(IOException ex) {
+ }
+ dropConnection();
+ // TODO Break links between fsm and session!
+ } else {
+ isAS4Capability = isAdvAS4Capability && open.getAS4Capability().isPresent();
+ remoteIdentifier = open.getIdentifier();
+ fsm.getCurrentState().openMsg(open);
+ }
break;
case UPDATE: {
BGPUpdate update = new BGPUpdate(this, packet.getMessage());