package com.lumaserv.bgp; import com.lumaserv.bgp.protocol.AFI; import com.lumaserv.bgp.protocol.BGPPacket; import com.lumaserv.bgp.protocol.SAFI; import com.lumaserv.bgp.protocol.message.BGPNotification; import com.lumaserv.bgp.protocol.message.BGPOpen; import com.lumaserv.bgp.protocol.message.BGPUpdate; import lombok.Getter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; public class BGPSession implements Runnable { @Getter final BGPSessionConfiguration configuration; final String host; final int port; Socket socket; InputStream inputStream; OutputStream outputStream; @Getter boolean closed; boolean outgoing; BGPFsm fsm; Thread thread; public BGPSession(Socket socket, BGPSessionConfiguration configuration, BGPFsm fsm) throws IOException { this.configuration = configuration; this.socket = socket; this.inputStream = socket.getInputStream(); this.outputStream = socket.getOutputStream(); this.fsm = fsm; this.host = null; this.port = -1; } public BGPSession(BGPSessionConfiguration configuration, BGPFsm fsm, String host, int port) throws IOException { this.configuration = configuration; this.fsm = fsm; this.host = host; this.port = port; } public void automaticStop() { fsm.getCurrentState().automaticStop(); } public void keepAlive() { try { outputStream.write(new BGPPacket().setType(BGPPacket.Type.KEEPALIVE).setMessage(new byte[0]).build()); } catch (IOException e) { e.printStackTrace(); } } private void handle(BGPPacket packet) { switch (packet.getType()) { case NOTIFICATION: BGPNotification notif = new BGPNotification(packet.getMessage()); if (notif.getMajorErrorCode() == BGPNotification.Error.MESSAGE_HEADER_ERROR.getCode() && notif.getMinorErrorCode() == BGPNotification.OpenMessageError.UNSUPPORTED_VERSION_NUMBER.getCode()) fsm.getCurrentState().notifMsgVerErr(notif); else fsm.getCurrentState().notifMsg(notif); break; case KEEPALIVE: fsm.getCurrentState().keepAliveMsg(); //keepAlive(); break; case OPEN: BGPOpen open = new BGPOpen(packet.getMessage()); fsm.getCurrentState().openMsg(open); break; case UPDATE: { BGPUpdate update = new BGPUpdate(packet.getMessage()); fsm.getCurrentState().updateMsg(update); configuration.getListener().onUpdate(this, update); break; } } } public void startIncoming() { outgoing = false; thread = new Thread(this); thread.start(); } public void startOutgoing() { outgoing = true; thread = new Thread(this); thread.start(); } void sendNotification(BGPNotification notification) throws IOException { outputStream.write(new BGPPacket().setType(BGPPacket.Type.NOTIFICATION).setMessage(notification.build()).build()); } void sendOpen(BGPOpen request) throws IOException { outputStream.write(new BGPPacket().setType(BGPPacket.Type.OPEN).setMessage(request.build()).build()); System.out.println("Sent open"); } public void sendOpen() throws IOException { BGPOpen.Capabilities caps = new BGPOpen.Capabilities(); caps.getCapabilities().add(new BGPOpen.MultiprotocolExtensionCapability(AFI.IPV4.getValue(), SAFI.UNICAST.getValue())); caps.getCapabilities().add(new BGPOpen.MultiprotocolExtensionCapability(AFI.IPV6.getValue(), SAFI.UNICAST.getValue())); BGPOpen request = new BGPOpen() .setAsn(configuration.getLocalAs()) .setHoldTime(BGPFsm.CONFIG_HOLD_TIME) .setVersion(BGPFsm.CONFIG_VERSION) .setIdentifier(configuration.getLocalIdentifier()); request.getOptionalParameters().add(caps); sendOpen(request); } public void retryConnection() { if (!socket.isConnected()) { try { socket.close(); } catch (IOException ex) { ex.printStackTrace(); throw new RuntimeException(ex); } } } public void dropConnection() { closed = true; try { if (outputStream != null) outputStream.close(); if (inputStream != null) inputStream.close(); socket.close(); } catch (IOException ex) { ex.printStackTrace(); throw new RuntimeException(ex); } } public void run() { try { if (socket == null) { while (true) { try { System.out.println("Outgoing"); socket = new Socket(); socket.connect(new InetSocketAddress(host, port)); break; } catch(IOException ex) { if (closed) { throw new IOException("Closed", ex); } } } System.out.println("Outgoing accepted"); inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); fsm.getCurrentState().tcpCRAcked(); } else { System.out.println("Incoming"); fsm.getCurrentState().tcpConnectionConfirmed(); } while (!closed) { handle(BGPPacket.read(inputStream)); } System.out.println("Closed!"); } catch (IOException ex) { if (!closed) { fsm.getCurrentState().tcpConnectionFails(); ex.printStackTrace(); } closed = true; configuration.getListener().onClose(this); } } }