KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > server > OutgoingServerSession


1 /**
2  * $RCSfile: OutgoingServerSession.java,v $
3  * $Revision: 1.12 $
4  * $Date: 2005/07/26 16:25:11 $
5  *
6  * Copyright (C) 2004 Jive Software. All rights reserved.
7  *
8  * This software is published under the terms of the GNU Public License (GPL),
9  * a copy of which is included in this distribution.
10  */

11
12 package org.jivesoftware.messenger.server;
13
14 import org.jivesoftware.messenger.*;
15 import org.jivesoftware.messenger.auth.UnauthorizedException;
16 import org.jivesoftware.util.LocaleUtils;
17 import org.jivesoftware.util.Log;
18 import org.xmpp.packet.JID;
19 import org.xmpp.packet.Packet;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.regex.Pattern JavaDoc;
25
26 /**
27  * Server-to-server communication is done using two TCP connections between the servers. One
28  * connection is used for sending packets while the other connection is used for receiving packets.
29  * The <tt>OutgoingServerSession</tt> represents the connection to a remote server that will only
30  * be used for sending packets.<p>
31  *
32  * Currently only the Server Dialback method is being used for authenticating with the remote
33  * server. Use {@link #authenticateDomain(String, String)} to create a new connection to a remote
34  * server that will be used for sending packets to the remote server from the specified domain.
35  * Only the authenticated domains with the remote server will be able to effectively send packets
36  * to the remote server. The remote server will reject and close the connection if a
37  * non-authenticated domain tries to send a packet through this connection.<p>
38  *
39  * Once the connection has been established with the remote server and at least a domain has been
40  * authenticated then a new route will be added to the routing table for this connection. For
41  * optimization reasons the same outgoing connection will be used even if the remote server has
42  * several hostnames. However, different routes will be created in the routing table for each
43  * hostname of the remote server.
44  *
45  * @author Gaston Dombiak
46  */

47 public class OutgoingServerSession extends Session {
48
49     /**
50      * Regular expression to ensure that the hostname contains letters.
51      */

52     private static Pattern JavaDoc pattern = Pattern.compile("[a-zA-Z]");
53
54     private Collection JavaDoc<String JavaDoc> authenticatedDomains = new ArrayList JavaDoc<String JavaDoc>();
55     private Collection JavaDoc<String JavaDoc> hostnames = new ArrayList JavaDoc<String JavaDoc>();
56     private OutgoingServerSocketReader socketReader;
57
58     /**
59      * Creates a new outgoing connection to the specified hostname if no one exists. The port of
60      * the remote server could be configured by setting the <b>xmpp.server.socket.remotePort</b>
61      * property or otherwise the standard port 5269 will be used. Either a new connection was
62      * created or already existed the specified hostname will be authenticated with the remote
63      * server. Once authenticated the remote server will start accepting packets from the specified
64      * domain.<p>
65      *
66      * The Server Dialback method is currently the only implemented method for server-to-server
67      * authentication. This implies that the remote server will ask the Authoritative Server
68      * to verify the domain to authenticate. Most probably this server will act as the
69      * Authoritative Server. See {@link IncomingServerSession} for more information.
70      *
71      * @param domain the local domain to authenticate with the remote server.
72      * @param hostname the hostname of the remote server.
73      * @return True if the domain was authenticated by the remote server.
74      */

75     public static boolean authenticateDomain(String JavaDoc domain, String JavaDoc hostname) {
76         if (hostname == null || hostname.length() == 0 || hostname.trim().indexOf(' ') > -1) {
77             // Do nothing if the target hostname is empty, null or contains whitespaces
78
return false;
79         }
80         try {
81             // Check if the remote hostname is in the blacklist
82
if (!RemoteServerManager.canAccess(hostname)) {
83                 return false;
84             }
85
86             // Check if a session already exists to the desired hostname (i.e. remote server). If
87
// no one exists then create a new session. The same session will be used for the same
88
// hostname for all the domains to authenticate
89
SessionManager sessionManager = SessionManager.getInstance();
90             OutgoingServerSession session = sessionManager.getOutgoingServerSession(hostname);
91             if (session == null) {
92                 // Try locating if the remote server has previously authenticated with this server
93
IncomingServerSession incomingSession = sessionManager.getIncomingServerSession(
94                         hostname);
95                 if (incomingSession != null) {
96                     for (String JavaDoc otherHostname : incomingSession.getValidatedDomains()) {
97                         session = sessionManager.getOutgoingServerSession(otherHostname);
98                         if (session != null) {
99                             // A session to the same remote server but with different hostname
100
// was found. Use this session and add the new hostname to the session
101
session.addHostname(hostname);
102                             break;
103                         }
104                     }
105                 }
106             }
107             if (session == null) {
108                 int port = RemoteServerManager.getPortForServer(hostname);
109                 // No session was found to the remote server so make sure that only one is created
110
synchronized (hostname.intern()) {
111                     session = sessionManager.getOutgoingServerSession(hostname);
112                     if (session == null) {
113                         session =
114                                 new ServerDialback().createOutgoingSession(domain, hostname, port);
115                         if (session != null) {
116                             // Add the new hostname to the list of names that the server may have
117
session.addHostname(hostname);
118                             // Add the validated domain as an authenticated domain
119
session.addAuthenticatedDomain(domain);
120                             // Notify the SessionManager that a new session has been created
121
sessionManager.outgoingServerSessionCreated(session);
122                             return true;
123                         }
124                         else {
125                             // Ensure that the hostname is not an IP address (i.e. contains chars)
126
if (!pattern.matcher(hostname).find()) {
127                                 return false;
128                             }
129                             // Check if hostname is a subdomain of an existing outgoing session
130
for (String JavaDoc otherHost : sessionManager.getOutgoingServers()) {
131                                 if (hostname.contains(otherHost)) {
132                                     session = sessionManager.getOutgoingServerSession(otherHost);
133                                     // Add the new hostname to the found session
134
session.addHostname(hostname);
135                                     return true;
136                                 }
137                             }
138                             // Try to establish a connection to candidate hostnames. Iterate on the
139
// substring after the . and try to establish a connection. If a
140
// connection is established then the same session will be used for
141
// sending packets to the "candidate hostname" as well as for the
142
// requested hostname (i.e. the subdomain of the candidate hostname)
143
// This trick is useful when remote servers haven't registered in their
144
// DNSs an entry for their subdomains
145
int index = hostname.indexOf('.');
146                             while (index > -1 && index < hostname.length()) {
147                                 String JavaDoc newHostname = hostname.substring(index + 1);
148                                 String JavaDoc serverName = XMPPServer.getInstance().getServerInfo()
149                                         .getName();
150                                 if ("com".equals(newHostname) || "net".equals(newHostname) ||
151                                         "org".equals(newHostname) ||
152                                         "gov".equals(newHostname) ||
153                                         "edu".equals(newHostname) ||
154                                         serverName.equals(newHostname)) {
155                                     return false;
156                                 }
157                                 session =
158                                         new ServerDialback().createOutgoingSession(domain, newHostname, port);
159                                 if (session != null) {
160                                     // Add the new hostname to the list of names that the server may have
161
session.addHostname(hostname);
162                                     // Add the validated domain as an authenticated domain
163
session.addAuthenticatedDomain(domain);
164                                     // Notify the SessionManager that a new session has been created
165
sessionManager.outgoingServerSessionCreated(session);
166                                     // Add the new hostname to the found session
167
session.addHostname(newHostname);
168                                     return true;
169                                 }
170                                 else {
171                                     index = hostname.indexOf('.', index + 1);
172                                 }
173                             }
174                             return false;
175                         }
176                     }
177                 }
178             }
179             if (session.getAuthenticatedDomains().contains(domain)) {
180                 // Do nothing since the domain has already been authenticated
181
return true;
182             }
183             // A session already exists so authenticate the domain using that session
184
ServerDialback method = new ServerDialback(session.getConnection(), domain);
185             if (method.authenticateDomain(session.socketReader, domain, hostname,
186                     session.getStreamID().getID())) {
187                 // Add the validated domain as an authenticated domain
188
session.addAuthenticatedDomain(domain);
189                 return true;
190             }
191         }
192         catch (Exception JavaDoc e) {
193             Log.error("Error authenticating domain with remote server: " + hostname, e);
194         }
195         return false;
196     }
197
198     OutgoingServerSession(String JavaDoc serverName, Connection connection,
199             OutgoingServerSocketReader socketReader, StreamID streamID) {
200         super(serverName, connection, streamID);
201         this.socketReader = socketReader;
202         socketReader.setSession(this);
203     }
204
205     public void process(Packet packet) throws UnauthorizedException, PacketException {
206         if (conn != null && !conn.isClosed()) {
207             try {
208                 conn.deliver(packet);
209             }
210             catch (Exception JavaDoc e) {
211                 Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
212             }
213         }
214     }
215
216     /**
217      * Returns a collection with all the domains, subdomains and virtual hosts that where
218      * authenticated. The remote server will accept packets sent from any of these domains,
219      * subdomains and virtual hosts.
220      *
221      * @return domains, subdomains and virtual hosts that where validated.
222      */

223     public Collection JavaDoc<String JavaDoc> getAuthenticatedDomains() {
224         return Collections.unmodifiableCollection(authenticatedDomains);
225     }
226
227     /**
228      * Adds a new authenticated domain, subdomain or virtual host to the list of
229      * authenticated domains for the remote server. The remote server will accept packets
230      * sent from this new authenticated domain.
231      *
232      * @param domain the new authenticated domain, subdomain or virtual host to add.
233      */

234     public void addAuthenticatedDomain(String JavaDoc domain) {
235         authenticatedDomains.add(domain);
236     }
237
238     /**
239      * Removes an authenticated domain from the list of authenticated domains. The remote
240      * server will no longer be able to accept packets sent from the removed domain, subdomain or
241      * virtual host.
242      *
243      * @param domain the domain, subdomain or virtual host to remove from the list of
244      * authenticated domains.
245      */

246     public void removeAuthenticatedDomain(String JavaDoc domain) {
247         authenticatedDomains.remove(domain);
248     }
249
250     /**
251      * Returns the list of hostnames related to the remote server. This tracking is useful for
252      * reusing the same session for the same remote server even if the server has many names.
253      *
254      * @return the list of hostnames related to the remote server.
255      */

256     public Collection JavaDoc<String JavaDoc> getHostnames() {
257         return Collections.unmodifiableCollection(hostnames);
258     }
259
260     /**
261      * Adds a new hostname to the list of known hostnames of the remote server. This tracking is
262      * useful for reusing the same session for the same remote server even if the server has
263      * many names.
264      *
265      * @param hostname the new known name of the remote server
266      */

267     private void addHostname(String JavaDoc hostname) {
268         if (hostnames.add(hostname)) {
269             // Register the outgoing session in the SessionManager. If the session
270
// was already registered nothing happens
271
sessionManager.registerOutgoingServerSession(hostname, this);
272             // Add a new route for this new session
273
XMPPServer.getInstance().getRoutingTable().addRoute(new JID(hostname), this);
274         }
275     }
276
277 }
278
Popular Tags