1 /**
2 * This file is part of Waarp Project.
3 *
4 * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the
5 * COPYRIGHT.txt in the distribution for a full listing of individual contributors.
6 *
7 * All Waarp Project is free software: you can redistribute it and/or modify it under the terms of
8 * the GNU General Public License as published by the Free Software Foundation, either version 3 of
9 * the License, or (at your option) any later version.
10 *
11 * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
12 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 * Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along with Waarp . If not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18 package org.waarp.ftp.core.session;
19
20 import java.net.InetAddress;
21 import java.net.InetSocketAddress;
22 import java.util.concurrent.ConcurrentHashMap;
23
24 import io.netty.channel.Channel;
25 import org.waarp.common.logging.WaarpLogger;
26 import org.waarp.common.logging.WaarpLoggerFactory;
27 import org.waarp.ftp.core.utils.FtpChannelUtils;
28
29 /**
30 * Class that allows to retrieve a session when a connection occurs on the Data network based on the {@link InetAddress} of the
31 * remote client and the {@link InetSocketAddress} of the server for
32 * Passive and reverse for Active connections. This is particularly useful for Passive mode
33 * connection since there is no way to pass the session to the connected channel without this
34 * reference.
35 *
36 * @author Frederic Bregier
37 *
38 */
39 public class FtpSessionReference {
40 /**
41 * Internal Logger
42 */
43 private static final WaarpLogger logger = WaarpLoggerFactory
44 .getLogger(FtpSessionReference.class);
45
46 /**
47 * Index of FtpSession References
48 *
49 * @author Frederic Bregier
50 *
51 */
52 public static class P2PAddress {
53 /**
54 * Remote Inet Address (no port)
55 */
56 public InetAddress ipOnly;
57
58 /**
59 * Local Inet Socket Address (with port)
60 */
61 public InetSocketAddress fullIp;
62
63 /**
64 * Constructor from Channel
65 *
66 * @param channel
67 */
68 public P2PAddress(Channel channel) {
69 ipOnly = FtpChannelUtils.getRemoteInetAddress(channel);
70 fullIp = (InetSocketAddress) channel.localAddress();
71 }
72
73 /**
74 * Constructor from addresses
75 *
76 * @param address
77 * @param inetSocketAddress
78 */
79 public P2PAddress(InetAddress address,
80 InetSocketAddress inetSocketAddress) {
81 ipOnly = address;
82 fullIp = inetSocketAddress;
83 }
84
85 /**
86 *
87 * @return True if the P2Paddress is valid
88 */
89 public boolean isValid() {
90 return ipOnly != null && fullIp != null;
91 }
92
93 @Override
94 public boolean equals(Object arg0) {
95 if (arg0 == null) {
96 return false;
97 }
98 if (arg0 instanceof P2PAddress) {
99 P2PAddress p2paddress = (P2PAddress) arg0;
100 if (p2paddress.isValid() && isValid()) {
101 return p2paddress.fullIp.equals(fullIp) &&
102 p2paddress.ipOnly.equals(ipOnly);
103 }
104 }
105 return false;
106 }
107
108 @Override
109 public int hashCode() {
110 return fullIp.hashCode() + ipOnly.hashCode();
111 }
112
113 }
114
115 /**
116 * Reference of FtpSession from InetSocketAddress
117 */
118 private final ConcurrentHashMap<P2PAddress, FtpSession> hashMap = new ConcurrentHashMap<P2PAddress, FtpSession>();
119
120 /**
121 * Constructor
122 *
123 */
124 public FtpSessionReference() {
125 }
126
127 /**
128 * Add a session from a couple of addresses
129 *
130 * @param ipOnly
131 * @param fullIp
132 * @param session
133 */
134 public void setNewFtpSession(InetAddress ipOnly, InetSocketAddress fullIp,
135 FtpSession session) {
136 P2PAddress pAddress = new P2PAddress(ipOnly, fullIp);
137 if (!pAddress.isValid()) {
138 logger.error("Couple invalid in setNewFtpSession: " + ipOnly +
139 " : " + fullIp);
140 return;
141 }
142 hashMap.put(pAddress, session);
143 // logger.debug("Add: {} {}", ipOnly, fullIp);
144 }
145
146 /**
147 * Return and remove the FtpSession
148 *
149 * @param channel
150 * @return the FtpSession if it exists associated to this channel
151 */
152 public FtpSession getActiveFtpSession(Channel channel, boolean remove) {
153 // First check Active connection
154 P2PAddress pAddress = new P2PAddress(((InetSocketAddress) channel
155 .localAddress()).getAddress(), (InetSocketAddress) channel
156 .remoteAddress());
157 if (!pAddress.isValid()) {
158 logger.error("Couple invalid in getActiveFtpSession: " + channel +
159 channel.localAddress() + channel.remoteAddress());
160 return null;
161 }
162 // logger.debug("Get: {} {}", pAddress.ipOnly, pAddress.fullIp);
163 if (remove) {
164 return hashMap.remove(pAddress);
165 } else {
166 return hashMap.get(pAddress);
167 }
168 }
169
170 /**
171 * Return and remove the FtpSession
172 *
173 * @param channel
174 * @return the FtpSession if it exists associated to this channel
175 */
176 public FtpSession getPassiveFtpSession(Channel channel, boolean remove) {
177 // First check passive connection
178 P2PAddress pAddress = new P2PAddress(channel);
179 if (!pAddress.isValid()) {
180 logger.error("Couple invalid in getPassiveFtpSession: " + channel);
181 return null;
182 }
183 // logger.debug("Get: {} {}", pAddress.ipOnly, pAddress.fullIp);
184 if (remove) {
185 return hashMap.remove(pAddress);
186 } else {
187 return hashMap.get(pAddress);
188 }
189 }
190
191 /**
192 * Remove the FtpSession from couple of addresses
193 *
194 * @param ipOnly
195 * @param fullIp
196 */
197 public void delFtpSession(InetAddress ipOnly, InetSocketAddress fullIp) {
198 P2PAddress pAddress = new P2PAddress(ipOnly, fullIp);
199 if (!pAddress.isValid()) {
200 logger.error("Couple invalid in delFtpSession: " + ipOnly + " : " +
201 fullIp);
202 return;
203 }
204 // logger.debug("Del: {} {}", pAddress.ipOnly, pAddress.fullIp);
205 hashMap.remove(pAddress);
206 }
207
208 /**
209 * Test if the couple of addresses is already in the hashmap (only for Active)
210 *
211 * @param ipOnly
212 * @param fullIp
213 * @return True if already presents
214 */
215 public boolean contains(InetAddress ipOnly, InetSocketAddress fullIp) {
216 P2PAddress pAddress = new P2PAddress(ipOnly, fullIp);
217 if (!pAddress.isValid()) {
218 logger.error("Couple invalid in contains: " + ipOnly + " : " +
219 fullIp);
220 return false;
221 }
222 // logger.debug("Contains: {} {}", pAddress.ipOnly, pAddress.fullIp);
223 return hashMap.containsKey(pAddress);
224 }
225
226 /**
227 *
228 * @return the number of active sessions
229 */
230 public int sessionsNumber() {
231 return hashMap.size();
232 }
233 }