2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.framework;
10 import io.netty.channel.Channel;
12 import java.io.IOException;
13 import java.net.Inet4Address;
14 import java.net.Inet6Address;
15 import java.net.InetAddress;
16 import java.net.InetSocketAddress;
18 import java.util.Timer;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
23 import com.google.common.collect.BiMap;
24 import com.google.common.collect.HashBiMap;
25 import com.google.common.collect.Maps;
28 * Representation of a server, created by {@link Dispatcher}. Should be extended by a protocol specific server
31 public final class ProtocolServer implements SessionParent {
33 private static final Logger logger = LoggerFactory.getLogger(ProtocolServer.class);
35 private static final int SESSIONS_LIMIT = 255;
37 private final InetSocketAddress serverAddress;
39 private final ProtocolConnectionFactory connectionFactory;
40 private final ProtocolSessionFactory<?> sessionFactory;
43 * Maps clients of this server to their address. The client is represented as PCEP session. Used BiMap for
44 * implementation to allow easy manipulation with both InetSocketAddress and PCEPSessionImpl representing a key.
46 private final BiMap<InetSocketAddress, ProtocolSession> sessions;
48 private final Map<InetSocketAddress, Integer> sessionIds;
50 private final Dispatcher parent;
53 * Creates a Protocol server.
55 * @param address address to which this server is bound
56 * @param connectionFactory factory for connection specific properties
57 * @param parent Dispatcher that created this server
58 * @param sessionFactory factory for sessions
60 public ProtocolServer(final InetSocketAddress address, final ProtocolConnectionFactory connectionFactory,
61 final ProtocolSessionFactory<?> sessionFactory, final Dispatcher parent) {
62 this.serverAddress = address;
63 this.sessions = HashBiMap.create();
64 this.connectionFactory = connectionFactory;
65 this.sessionFactory = sessionFactory;
67 this.sessionIds = Maps.newHashMap();
71 * Creates a session. This method is called after the server accepts incoming client connection. A session is
72 * created for each client. If a session for a client (represented by the address) was already created, return this,
73 * else create a new one.
75 * @param clientAddress IP address of the client
76 * @param timer Timer common for all sessions
77 * @return new or existing PCEPSession
78 * @see <a href="http://tools.ietf.org/html/rfc5440#appendix-A">RFC</a>
80 public ProtocolSession createSession(final Timer timer, final Channel channel) {
81 ProtocolSession session = null;
82 final InetSocketAddress clientAddress = (InetSocketAddress) channel.remoteAddress();
83 if (this.sessions.containsKey(clientAddress)) { // when the session is created, the key is the InetSocketAddress
84 session = this.sessions.get(clientAddress);
85 if (compareTo(this.serverAddress.getAddress(), clientAddress.getAddress()) > 0) {
88 } catch (final IOException e) {
89 logger.error("Could not close session: {}.", session);
93 final int sessionId = getNextId(this.sessionIds.get(clientAddress), SESSIONS_LIMIT - 1);
94 session = this.sessionFactory.getProtocolSession(this, timer, this.connectionFactory.createProtocolConnection(clientAddress),
95 sessionId, channel.pipeline().context(ProtocolSessionOutboundHandler.class));
96 this.sessionIds.put(clientAddress, sessionId);
98 this.sessions.put(clientAddress, session);
103 public synchronized void close() throws IOException {
104 ((DispatcherImpl) this.parent).onServerClosed(this);
105 logger.debug("Closed server {}.", this);
109 public synchronized void onSessionClosed(final ProtocolSession session) {
110 this.sessions.inverse().remove(session); // when the session is closed, the key is the instance of the session
111 logger.debug("Closed session {}.", session);
114 private static int getNextId(Integer lastId, final int maxId) {
115 return (lastId == null || maxId == lastId) ? 0 : ++lastId;
119 * Compares byte array representations of two InetAddresses.
123 * @throws IllegalArgumentException if InetAddresses don't belong to the same subclass of InetAddress.
124 * @return 1 if addrOne is greater than addrTwo, 0 if they are the same, -1 if addrOne is lower than addrTwo
126 private static int compareTo(final InetAddress addrOne, final InetAddress addrTwo) {
127 if ((addrOne instanceof Inet4Address && addrOne instanceof Inet6Address)
128 || (addrOne instanceof Inet6Address && addrOne instanceof Inet4Address)) {
129 throw new IllegalArgumentException("Cannot compare InetAddresses. They both have to be the same subclass of InetAddress.");
131 final byte[] byteOne = addrOne.getAddress();
132 final byte[] byteTwo = addrTwo.getAddress();
133 for (int i = 0; i < byteOne.length; i++) {
134 if (byteOne[i] > byteTwo[i])
136 else if (byteOne[i] < byteTwo[i])
143 public String toString() {
144 return "ProtocolServer [serverAddress=" + this.serverAddress + ", hashCode()=" + hashCode() + "]";
148 public int hashCode() {
149 final int prime = 31;
151 result = prime * result + ((this.serverAddress == null) ? 0 : this.serverAddress.hashCode());
156 public boolean equals(final Object obj) {
161 if (getClass() != obj.getClass())
163 final ProtocolServer other = (ProtocolServer) obj;
164 if (this.serverAddress == null) {
165 if (other.serverAddress != null)
167 } else if (!this.serverAddress.equals(other.serverAddress))