View Javadoc
1   package org.metricshub.ipmi.core.connection;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * IPMI Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 Verax Systems, MetricsHub
8    * ჻჻჻჻჻჻
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23   */
24  
25  import org.metricshub.ipmi.core.api.async.ConnectionHandle;
26  import org.metricshub.ipmi.core.api.sol.CipherSuiteSelectionHandler;
27  import org.metricshub.ipmi.core.api.sync.IpmiConnector;
28  import org.metricshub.ipmi.core.coding.commands.PrivilegeLevel;
29  import org.metricshub.ipmi.core.coding.security.CipherSuite;
30  
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import java.net.InetAddress;
35  import java.util.List;
36  import java.util.concurrent.ConcurrentHashMap;
37  
38  /**
39   * Manages multiple {@link Session}s.
40   */
41  public class SessionManager {
42  
43      private static final Logger logger = LoggerFactory.getLogger(SessionManager.class);
44  
45      private static Integer sessionId = 100;
46  
47      /**
48       * The session ID generated by the {@link SessionManager}.
49       * Auto-incremented.
50       */
51      public static synchronized int generateSessionId() {
52          sessionId %= (Integer.MAX_VALUE / 4);
53          return sessionId++;
54      }
55  
56      public static Session establishSession(IpmiConnector connector, String remoteHost, int remotePort, String user, String password,
57                                             CipherSuiteSelectionHandler cipherSuiteSelectionHandler) throws SessionException {
58          ConnectionHandle handle = null;
59  
60          try {
61              handle = connector.createConnection(InetAddress.getByName(remoteHost), remotePort);
62  
63              List<CipherSuite> availableCipherSuites = connector.getAvailableCipherSuites(handle);
64              CipherSuite cipherSuite = cipherSuiteSelectionHandler.choose(availableCipherSuites);
65  
66              if (cipherSuite == null) {
67                  cipherSuite = CipherSuite.getEmpty();
68              }
69  
70              connector.getChannelAuthenticationCapabilities(handle, cipherSuite, PrivilegeLevel.Administrator);
71  
72              return connector.openSession(handle, user, password, null);
73          } catch (Exception e) {
74              closeConnection(connector, handle);
75  
76              throw new SessionException("Cannot create new session due to exception", e);
77          }
78      }
79  
80      private static void closeConnection(IpmiConnector connector, ConnectionHandle handle) {
81          try {
82              if (connector != null && handle != null) {
83                  connector.closeSession(handle);
84                  connector.tearDown();
85              }
86          } catch (Exception e) {
87              logger.error("Cannot close connection after exception thrown during session establishment.", e);
88          }
89      }
90  
91      private final ConcurrentHashMap<Integer, Session> sessionsPerConnectionHandle;
92  
93      public SessionManager() {
94          this.sessionsPerConnectionHandle = new ConcurrentHashMap<Integer, Session>();
95      }
96  
97      /**
98       * Either returns the {@link Session} registered for given connection, or creates new IPMI {@link Session}
99       * and registers it for the given connection handle, if no session was found for the connection.
100      *
101      * @param connectionHandle
102      *          handle of the connection, for which this session should be registered.
103      * @return newly created session object or session already registered for the connection
104      */
105     public Session registerSession(int sessionId, ConnectionHandle connectionHandle) {
106         if (connectionHandle.getUser() == null || connectionHandle.getRemoteAddress() == null) {
107             throw new IllegalArgumentException("Given connection handle is incomplete (lacks user or remote address)");
108         }
109 
110         Session newSession = new Session(sessionId, connectionHandle);
111         Session currentSession = sessionsPerConnectionHandle.putIfAbsent(connectionHandle.getHandle(), newSession);
112 
113         return currentSession != null ? currentSession : newSession;
114     }
115 
116     /**
117      * Unregisters session for given connection handle.
118      *
119      * @param connectionHandle
120      *          handle of the connection, for which the session should be unregistered.
121      */
122     public void unregisterSession(ConnectionHandle connectionHandle) {
123         sessionsPerConnectionHandle.remove(connectionHandle.getHandle());
124     }
125 
126     /**
127      * Returns session already bound to given connection handle fulfilling given criteria.
128      *
129      * @param remoteAddress
130      *          IP addres of the managed system
131      * @param remotePort
132      *          UDP port of the managed system
133      * @param user
134      *          IPMI user for whom the connection is established
135      * @return session object fulfilling given criteria, or null if no session was registered for such connection.
136      */
137     public Session getSessionForCriteria(InetAddress remoteAddress, int remotePort, String user) {
138         for (Session session : sessionsPerConnectionHandle.values()) {
139             ConnectionHandle sessionConnectionHandle = session.getConnectionHandle();
140 
141             if (sessionConnectionHandle.getUser().equals(user)
142                     && sessionConnectionHandle.getRemoteAddress().equals(remoteAddress)
143                     && sessionConnectionHandle.getRemotePort() == remotePort) {
144                 return session;
145             }
146         }
147 
148         return null;
149     }
150 }