Openfire S2S 经验分享

1、各Openfire服务器得设置不同的域名,即 ofProperty表xmpp.domain属性,如设置 192.168.1.46等。

2、Dialback提供一种弱身份验证的方式,要使用这种方式可以将 ofproperty表中“xmpp.server.tls.enabled” 设置为false,并将“xmpp.server.dialback.enabled”设置为true。

3、建立到对方的路由:

  LocalOutgoingServerSession类 authenticateDomain方法:

ExpandedBlockStart.gif View Code
 1  public  static boolean authenticateDomain(String domain, String hostname) {
 2     OutgoingServerSession session;           
 3     ......
 4     session = createOutgoingSession(domain, hostname, port);
 5      if (session !=  null) {
 6          //  Add the validated domain as an authenticated domain
 7          session.addAuthenticatedDomain(domain);
 8          //  Add the new hostname to the list of names that the server may have
 9          session.addHostname(hostname);
10          //  Notify the SessionManager that a new session has been created
11          sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
12          return  true;
13     }
14     ......
15 }    

   3.1 Socket探测对方5269端口是否开放。

       LocalOutgoingServerSession类 createOutgoingSession方法:

ExpandedBlockStart.gif View Code
 1  private  static LocalOutgoingServerSession createOutgoingSession(String domain, String hostname,
 2              int port) {
 3          boolean useTLS = JiveGlobals.getBooleanProperty("xmpp.server.tls.enabled",  true);
 4         RemoteServerConfiguration configuration = RemoteServerManager.getConfiguration(hostname);
 5          if (configuration !=  null) {
 6              //  TODO Use the specific TLS configuration for this remote server
 7               // useTLS = configuration.isTLSEnabled();
 8          }
 9 
10          //  Connect to remote server using XMPP 1.0 (TLS + SASL EXTERNAL or TLS + server dialback or server dialback)
11          SocketConnection connection =  null;
12         String realHostname =  null;
13          int realPort = port;
14         Socket socket =  new Socket();
15          try {
16              //  Get the real hostname to connect to using DNS lookup of the specified hostname
17              DNSUtil.HostAddress address = DNSUtil.resolveXMPPServerDomain(hostname, port);
18             realHostname = address.getHost();
19             realPort = address.getPort();
20             Log.debug("LocalOutgoingServerSession: OS - Trying to connect to " + hostname + ":" + port +
21                     "(DNS lookup: " + realHostname + ":" + realPort + ")");
22              //  Establish a TCP connection to the Receiving Server
23              socket.connect( new InetSocketAddress(realHostname, realPort),
24                     RemoteServerManager.getSocketTimeout());
25             Log.debug("LocalOutgoingServerSession: OS - Plain connection to " + hostname + ":" + port + " successful");
26         }
27          catch (Exception e) {
28             Log.error("Error trying to connect to remote server: " + hostname +
29                     "(DNS lookup: " + realHostname + ":" + realPort + ")", e);
30              return  null;
31         }

     3.2 尝试server dialback(XMPP 1.0),建立信任通道。
         3.2.1 LocalOutgoingServerSession类 createOutgoingSession方法:

ExpandedBlockStart.gif View Code
 1  //  Check if we are going to try server dialback (XMPP 1.0)
 2                       else  if (ServerDialback.isEnabled() && features.element("dialback") !=  null) {
 3                         Log.debug("LocalOutgoingServerSession: OS - About to try connecting using server dialback XMPP 1.0 with: " + hostname);
 4                         ServerDialback method =  new ServerDialback(connection, domain);
 5                         OutgoingServerSocketReader newSocketReader =  new OutgoingServerSocketReader(reader);                        
 6                          if (method.authenticateDomain(newSocketReader, domain, hostname, id)) {
 7                             Log.debug("LocalOutgoingServerSession: OS - SERVER DIALBACK XMPP 1.0 with " + hostname + " was successful");                            
 8                             StreamID streamID =  new BasicStreamIDFactory().createStreamID(id);
 9                             LocalOutgoingServerSession session =  new LocalOutgoingServerSession(domain, connection, newSocketReader, streamID);
10                             connection.init(session);
11                              //  Set the hostname as the address of the session
12                              session.setAddress( new JID( null, hostname,  null));                            
13                              return session;
14                         }
15                          else {
16                             Log.debug("LocalOutgoingServerSession: OS - Error, SERVER DIALBACK with " + hostname + " failed");
17                         }
18                     }
19                     

        3.2.2 ServerDialback类 authenticateDomain方法:

ExpandedBlockStart.gif View Code
 1  public boolean authenticateDomain(OutgoingServerSocketReader socketReader, String domain,
 2             String hostname, String id) {
 3         String key = AuthFactory.createDigest(id, getSecretkey());
 4         Log.debug( " ServerDialback: OS - Sent dialback key to host:  " + hostname +  "  id:  " + id +  "  from domain:  " +
 5                 domain);
 6 
 7         synchronized (socketReader) {
 8              //  Send a dialback key to the Receiving Server
 9              StringBuilder sb =  new StringBuilder();
10             sb.append( " <db:result ");
11             sb.append( "  from=\" ").append(domain).append( " \" ");
12             sb.append( "  to=\" ").append(hostname).append( " \"> ");
13             sb.append(key);
14             sb.append( " </db:result> ");
15             connection.deliverRawText(sb.toString());
16 
17              //  Process the answer from the Receiving Server
18               try {
19                 Element doc = socketReader.getElement(RemoteServerManager.getSocketTimeout(),
20                         TimeUnit.MILLISECONDS);
21                  if (doc ==  null) {
22                     Log.debug( " ServerDialback: OS - Time out waiting for answer in validation from:  " + hostname +
23                              "  id:  " +
24                             id +
25                              "  for domain:  " +
26                             domain);
27                      return  false;
28                 }
29                  else  if ( " db ".equals(doc.getNamespacePrefix()) &&  " result ".equals(doc.getName())) {
30                     boolean success =  " valid ".equals(doc.attributeValue( " type "));
31                     Log.debug( " ServerDialback: OS - Validation  " + (success ?  " GRANTED " :  " FAILED ") +  "  from:  " +
32                             hostname +
33                              "  id:  " +
34                             id +
35                              "  for domain:  " +
36                             domain);
37                      return success;
38                 }
39                  else {
40                     Log.debug( " ServerDialback: OS - Unexpected answer in validation from:  " + hostname +  "  id:  " +
41                             id +
42                              "  for domain:  " +
43                             domain +
44                              "  answer: " +
45                             doc.asXML());
46                      return  false;
47                 }
48             }
49              catch (InterruptedException e) {
50                 Log.debug( " ServerDialback: OS - Validation FAILED from:  " + hostname +
51                          "  id:  " +
52                         id +
53                          "  for domain:  " +
54                         domain, e);
55                  return  false;
56             }
57         }
58     }

 

4、加入路由表的serversCache缓存。如 session.addHostname(hostname);

    LocalOutgoingServerSession类 addHostname方法:

ExpandedBlockStart.gif View Code
1  public  void addHostname(String hostname) {
2         synchronized (hostnames) {
3             hostnames.add(hostname);
4         }
5          //  Add a new route for this new session
6          XMPPServer.getInstance().getRoutingTable().addServerRoute( new JID( null, hostname,  nulltrue),  this);
7     }

    RoutingTableImpl类 addServerRoute(JID route, LocalOutgoingServerSession destination)方法:

ExpandedBlockStart.gif View Code
 1  public  void addServerRoute(JID route, LocalOutgoingServerSession destination) {
 2         String address = route.getDomain();
 3         localRoutingTable.addRoute(address, destination);
 4         Lock  lock = CacheFactory.getLock(address, serversCache);
 5          try {
 6              lock. lock();
 7             serversCache.put(address, server.getNodeID().toByteArray());
 8         }
 9          finally {
10              lock.unlock();            
11         }
12     }


5、包再次路由,发往对方。

    5.1 OutgoingSessionPromise类 sendPacket(Packet packet)方法:        

ExpandedBlockStart.gif View Code
 1  private  void sendPacket(Packet packet) throws Exception {
 2              //  Create a connection to the remote server from the domain where the packet has been sent
 3              boolean created;
 4              //  Make sure that only one cluster node is creating the outgoing connection
 5               //  TODO: Evaluate why removing the oss part causes nasty s2s and lockup issues.
 6              Lock  lock = CacheFactory.getLock(domain+ " oss ", serversCache);
 7              try {
 8                  lock. lock();
 9                 created = LocalOutgoingServerSession
10                         .authenticateDomain(packet.getFrom().getDomain(), packet.getTo().getDomain());
11             }  finally {
12                  lock.unlock();
13             }
14              if (created) {
15                  if (!routingTable.hasServerRoute(packet.getTo())) {
16                      throw  new Exception( " Route created but not found!!! ");
17                 }
18                  //  A connection to the remote server was created so get the route and send the packet
19                  routingTable.routePacket(packet.getTo(), packet,  false);
20             }
21              else {
22                  throw  new Exception( " Failed to create connection to remote server ");
23             }
24         }

    5.2 RoutingTableImpl类 routePacket(JID jid, Packet packet, boolean fromServer)方法:

ExpandedBlockStart.gif View Code
 1  //  Packet sent to remote server
 2               byte[] nodeID = serversCache.get(jid.getDomain());
 3              if (nodeID !=  null) {
 4                  if (server.getNodeID().equals(nodeID)) {
 5                      //  This is a route to a remote server connected from this node
 6                       try {
 7                         localRoutingTable.getRoute(jid.getDomain()).process(packet);
 8                         routed =  true;
 9                     }  catch (UnauthorizedException e) {
10                         Log.error(e);
11                     }
12                 }
13                  else {
14                      //  This is a route to a remote server connected from other node
15                       if (remotePacketRouter !=  null) {
16                         routed = remotePacketRouter.routePacket(nodeID, jid, packet);
17                     }
18                 }
19             }
20              else {
21                  //  Return a promise of a remote session. This object will queue packets pending
22                   //  to be sent to remote servers
23                  OutgoingSessionPromise.getInstance().process(packet);
24                 routed =  true;
25             }

      5.3 通过SocketConnection类的deliver(Packet packet)发出:

ExpandedBlockStart.gif View Code
 1  public  void deliver(Packet packet)  throws UnauthorizedException, PacketException {
 2          if (isClosed()) {
 3             backupDeliverer.deliver(packet);
 4         }
 5          else {
 6              boolean errorDelivering =  false;
 7              boolean allowedToWrite =  false;
 8              try {
 9                 requestWriting();
10                 allowedToWrite =  true;
11                 xmlSerializer.write(packet.getElement());
12                  if (flashClient) {
13                     writer.write('\0');
14                 }
15                 xmlSerializer.flush();
16             }
17              catch (Exception e) {
18                 Log.debug("Error delivering packet" + "\n" +  this.toString(), e);
19                 errorDelivering =  true;
20             }
21              finally {
22                  if (allowedToWrite) {
23                     releaseWriting();
24                 }
25             }
26              if (errorDelivering) {
27                 close();
28                  //  Retry sending the packet again. Most probably if the packet is a
29                   //  Message it will be stored offline
30                  backupDeliverer.deliver(packet);
31             }
32              else {
33                 session.incrementServerPacketCount();
34             }
35         }
36     }

  

6、对方Openfire服务器在ServerSocketReader类的 packetReceived(Packet packet) 接收,并响应回包。

ExpandedBlockStart.gif View Code
 1  private  void packetReceived(Packet packet)  throws PacketRejectedException {
 2          if (packet.getTo() ==  null || packet.getFrom() ==  null) {
 3             Log.debug("Closing IncomingServerSession due to packet with no TO or FROM: " +
 4                     packet.toXML());
 5              //  Send a stream error saying that the packet includes no TO or FROM
 6              StreamError error =  new StreamError(StreamError.Condition.improper_addressing);
 7             connection.deliverRawText(error.toXML());
 8              //  Close the underlying connection
 9              connection.close();
10             open =  false;
11              throw  new PacketRejectedException("Packet with no TO or FROM attributes");
12         }
13          else  if (!((LocalIncomingServerSession) session).isValidDomain(packet.getFrom().getDomain())) {
14             Log.debug("Closing IncomingServerSession due to packet with invalid domain: " +
15                     packet.toXML());
16              //  Send a stream error saying that the packet includes an invalid FROM
17              StreamError error =  new StreamError(StreamError.Condition.invalid_from);
18             connection.deliverRawText(error.toXML());
19              //  Close the underlying connection
20              connection.close();
21             open =  false;
22              throw  new PacketRejectedException("Packet with no TO or FROM attributes");
23         }
24     }

 

转载于:https://www.cnblogs.com/huazai8204/archive/2011/12/21/2295669.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值