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;
17 import java.util.HashMap;
19 import java.util.Timer;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
24 import com.google.common.collect.BiMap;
25 import com.google.common.collect.HashBiMap;
28 * Representation of a server, created by {@link Dispatcher}. Should be extended by a protocol specific server
31 public 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;
51 * Creates a Protocol server.
53 * @param dispatcher Dispatcher
54 * @param address address to which this server is bound
55 * @param connectionFactory factory for connection specific properties
56 * @param channel server socket channel
57 * @param sessionFactory factory for sessions
58 * @param inputStreamFactory factory for input streams
60 public ProtocolServer(final InetSocketAddress address, final ProtocolConnectionFactory connectionFactory,
61 final ProtocolSessionFactory sessionFactory) {
62 this.serverAddress = address;
63 this.sessions = HashBiMap.create();
64 this.connectionFactory = connectionFactory;
65 this.sessionFactory = sessionFactory;
66 this.sessionIds = new HashMap<InetSocketAddress, Integer>();
70 * Creates a session. This method is called after the server accepts incoming client connection. A session is
71 * created for each client. If a session for a client (represented by the address) was already created, return this,
72 * else create a new one.
74 * @param clientAddress IP address of the client
75 * @param timer Timer common for all sessions
76 * @return new or existing PCEPSession
77 * @see <a href="http://tools.ietf.org/html/rfc5440#appendix-A">RFC</a>
79 public ProtocolSession createSession(final Timer timer, final Channel channel) {
80 ProtocolSession session = null;
81 final InetSocketAddress clientAddress = (InetSocketAddress) channel.remoteAddress();
82 if (this.sessions.containsKey(clientAddress)) { // when the session is created, the key is the InetSocketAddress
83 session = this.sessions.get(clientAddress);
84 if (compareTo(this.serverAddress.getAddress(), clientAddress.getAddress()) > 0) {
87 } catch (final IOException e) {
88 logger.error("Session {} could not be closed.", session);
92 final int sessionId = getNextId(this.sessionIds.get(clientAddress), SESSIONS_LIMIT - 1);
93 session = this.sessionFactory.getProtocolSession(this, timer, this.connectionFactory.createProtocolConnection(clientAddress),
94 sessionId, channel.pipeline().context(ProtocolSessionOutboundHandler.class));
95 this.sessionIds.put(clientAddress, sessionId);
97 this.sessions.put(clientAddress, session);
102 * Returns server address.
104 * @return server address
106 public InetSocketAddress getAddress() {
107 return this.serverAddress;
111 public synchronized void close() throws IOException {
113 logger.debug("Server {} closed.", this);
117 public synchronized void onSessionClosed(final ProtocolSession session) {
118 this.sessions.inverse().remove(session); // when the session is closed, the key is the instance of the session
121 private static int getNextId(Integer lastId, final int maxId) {
122 return (lastId == null || maxId == lastId) ? 0 : ++lastId;
126 * Compares byte array representations of two InetAddresses.
130 * @throws IllegalArgumentException if InetAddresses don't belong to the same subclass of InetAddress.
131 * @return 1 if addrOne is greater than addrTwo, 0 if they are the same, -1 if addrOne is lower than addrTwo
133 private static int compareTo(final InetAddress addrOne, final InetAddress addrTwo) {
134 if ((addrOne instanceof Inet4Address && addrOne instanceof Inet6Address)
135 || (addrOne instanceof Inet6Address && addrOne instanceof Inet4Address)) {
136 throw new IllegalArgumentException("Cannot compare InetAddresses. They both have to be the same subclass of InetAddress.");
138 final byte[] byteOne = addrOne.getAddress();
139 final byte[] byteTwo = addrTwo.getAddress();
140 for (int i = 0; i < byteOne.length; i++) {
141 if (byteOne[i] > byteTwo[i])
143 else if (byteOne[i] < byteTwo[i])
150 public String toString() {
151 return "ProtocolServer [serverAddress=" + this.serverAddress + ", hashCode()=" + hashCode() + "]";