1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.ftp.core.session;
21
22 import io.netty.channel.Channel;
23 import org.waarp.common.logging.SysErrLogger;
24 import org.waarp.common.logging.WaarpLogger;
25 import org.waarp.common.logging.WaarpLoggerFactory;
26 import org.waarp.ftp.core.utils.FtpChannelUtils;
27
28 import java.net.InetAddress;
29 import java.net.InetSocketAddress;
30 import java.net.UnknownHostException;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Enumeration;
34 import java.util.concurrent.ConcurrentHashMap;
35
36
37
38
39
40
41
42
43
44
45 public class FtpSessionReference {
46
47
48
49 private static final WaarpLogger logger =
50 WaarpLoggerFactory.getLogger(FtpSessionReference.class);
51
52 private static final byte[] LOOPBACK = { 0, 0, 0, 0 };
53 private static final byte[] LOOPBACK2 = { 127, 0, 0, 1 };
54 private static final InetAddress LOOPBACK_ADDRESS;
55
56 static {
57 InetAddress address = null;
58 try {
59 address = InetAddress.getByAddress(LOOPBACK2);
60 } catch (final UnknownHostException e) {
61 SysErrLogger.FAKE_LOGGER.ignoreLog(e);
62 }
63 LOOPBACK_ADDRESS = address;
64 }
65
66
67
68
69 public static class P2PAddress {
70
71
72
73 public final InetAddress ipOnly;
74
75
76
77
78 public final InetSocketAddress fullIp;
79
80 public final long creationTime = System.currentTimeMillis();
81
82
83
84
85
86
87 public P2PAddress(final Channel channel) {
88 InetAddress ip = FtpChannelUtils.getRemoteInetAddress(channel);
89 if (isLoopback(ip)) {
90 ipOnly = LOOPBACK_ADDRESS;
91 } else {
92 ipOnly = ip;
93 }
94 InetSocketAddress isa = (InetSocketAddress) channel.localAddress();
95 if (isLoopback(isa.getAddress())) {
96 fullIp = new InetSocketAddress(LOOPBACK_ADDRESS, isa.getPort());
97 } else {
98 fullIp = isa;
99 }
100 }
101
102
103
104
105
106
107
108 public P2PAddress(final InetAddress address,
109 final InetSocketAddress inetSocketAddress) {
110 if (isLoopback(address)) {
111 ipOnly = LOOPBACK_ADDRESS;
112 } else {
113 ipOnly = address;
114 }
115 if (isLoopback(inetSocketAddress.getAddress())) {
116 fullIp = new InetSocketAddress(LOOPBACK_ADDRESS,
117 inetSocketAddress.getPort());
118 } else {
119 fullIp = inetSocketAddress;
120 }
121 }
122
123
124
125
126 private final boolean isValid() {
127 return ipOnly != null && fullIp != null;
128 }
129
130 @Override
131 public final boolean equals(final Object o) {
132 if (o == null) {
133 return false;
134 }
135 if (o instanceof P2PAddress) {
136 final P2PAddress p2paddress = (P2PAddress) o;
137 if (p2paddress.isValid() && isValid()) {
138 boolean equal = p2paddress.fullIp.equals(fullIp) &&
139 p2paddress.ipOnly.equals(ipOnly);
140 if (!equal) {
141 boolean sameIp =
142 p2paddress.fullIp.getAddress().equals(fullIp.getAddress()) ||
143 (isLoopback(fullIp.getAddress()) &&
144 isLoopback(p2paddress.fullIp.getAddress()));
145 equal = sameIp && p2paddress.fullIp.getPort() == fullIp.getPort();
146 }
147 return equal;
148 }
149 }
150 return false;
151 }
152
153 @Override
154 public final int hashCode() {
155 return fullIp.hashCode() + ipOnly.hashCode();
156 }
157
158 @Override
159 public String toString() {
160 return ipOnly.toString() + "-" + fullIp.toString();
161 }
162 }
163
164 private static boolean isLoopback(final InetAddress inetAddress) {
165 return Arrays.equals(inetAddress.getAddress(), LOOPBACK2) ||
166 Arrays.equals(inetAddress.getAddress(), LOOPBACK) ||
167 inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress();
168 }
169
170
171
172
173 private final ConcurrentHashMap<P2PAddress, FtpSession> hashMap =
174 new ConcurrentHashMap<P2PAddress, FtpSession>();
175
176
177
178
179 public FtpSessionReference() {
180
181 }
182
183 private void cleanFtpSession() {
184
185 final long nowInPast = System.currentTimeMillis() - 10 * 60 * 1000;
186 ArrayList<P2PAddress> list = new ArrayList<P2PAddress>();
187 Enumeration<P2PAddress> enumeration = hashMap.keys();
188 while (enumeration.hasMoreElements()) {
189 final P2PAddress entry = enumeration.nextElement();
190 if (entry.creationTime < nowInPast) {
191 list.add(entry);
192 }
193 }
194 for (P2PAddress pAddress : list) {
195 hashMap.remove(pAddress);
196 }
197 list.clear();
198 }
199
200
201
202
203
204
205
206
207 public final void setNewFtpSession(final InetAddress ipOnly,
208 final InetSocketAddress fullIp,
209 final FtpSession session) {
210 cleanFtpSession();
211 final P2PAddress pAddress = new P2PAddress(ipOnly, fullIp);
212 if (!pAddress.isValid()) {
213 logger.error(
214 "Couple invalid in setNewFtpSession: " + ipOnly + " : " + fullIp);
215 return;
216 }
217 hashMap.put(pAddress, session);
218 }
219
220
221
222
223
224
225
226
227 public final FtpSession getPassiveFtpSession(final Channel channel) {
228 cleanFtpSession();
229
230 final P2PAddress pAddress = new P2PAddress(channel);
231 if (!pAddress.isValid()) {
232 logger.error("Couple invalid in getPassiveFtpSession: " + channel);
233 return null;
234 }
235 return hashMap.remove(pAddress);
236 }
237
238
239
240
241
242
243 public final FtpSession findPassive(final Channel channel) {
244 cleanFtpSession();
245 InetAddress remote =
246 ((InetSocketAddress) channel.remoteAddress()).getAddress();
247 if (isLoopback(remote)) {
248 remote = LOOPBACK_ADDRESS;
249 }
250 final int port = ((InetSocketAddress) channel.localAddress()).getPort();
251 P2PAddress entry = null;
252 Enumeration<P2PAddress> enumeration = hashMap.keys();
253 while (enumeration.hasMoreElements()) {
254 entry = enumeration.nextElement();
255 if (entry.fullIp.getPort() == port && (entry.ipOnly.equals(remote) ||
256 Arrays.equals(
257 entry.ipOnly.getAddress(),
258 remote.getAddress()))) {
259 break;
260 }
261 entry = null;
262 }
263 if (entry != null) {
264 logger.debug("Found from port only: {}", entry);
265 return hashMap.remove(entry);
266 }
267 return null;
268 }
269
270
271
272
273
274
275 public final void delFtpSession(final Channel channel) {
276 cleanFtpSession();
277 final P2PAddress pAddress;
278 pAddress = new P2PAddress(channel);
279 if (!pAddress.isValid()) {
280 return;
281 }
282 hashMap.remove(pAddress);
283 }
284
285
286
287
288
289
290
291 public final void delFtpSession(final InetAddress ipOnly,
292 final InetSocketAddress fullIp) {
293 cleanFtpSession();
294 final P2PAddress pAddress = new P2PAddress(ipOnly, fullIp);
295 if (!pAddress.isValid()) {
296 logger.error(
297 "Couple invalid in delFtpSession: " + ipOnly + " : " + fullIp);
298 return;
299 }
300 hashMap.remove(pAddress);
301 }
302
303
304
305
306 public final int sessionsNumber() {
307 cleanFtpSession();
308 return hashMap.size();
309 }
310
311 }