Openfire S2S 连接建立与消息发送

原文地址:http://yjl49.iteye.com/blog/1452569

发送给其它服务器的消息由@domain 部分区分,在进入到服务器路由后在RoutingTableImpl.routePacket(Packet packet) 中与发送给本地服务器的消息分离。

Java代码 
  1. public void routePacket(JID jid,......){  
  2.   boolean routed = false;  
  3.   if(serverName.equals(jid.getDomain())){  
  4.      routed = routeToLocalDomain(jid,packet,fromServer);  
  5.   }  
  6.   else if(jid.getDomain().contains(serverName)){  
  7.      routed = routeToComponent(jid,packet,routed);  
  8.   }  
  9.   else{  
  10.      routed = routeToRemoteDomain(jid,packet,routed);  
  11.   }  
  12. }  
  13. ......  

在初次发送消息给外部服务器时两台服务器的连接还没有建立,这种情况下会将包交由一个OutgoingSessionPromise 对象来处理,将消息加入它的队列。

Java代码 
  1. private boolean routeToRomoteDomain(JID jid,Packet packet,boolean routed){  
  2.      byte[] nodeID = serverCache.get(jid.getDomain);  
  3.      if(nodeID!=null){  
  4.         ......  
  5.      }  
  6.      else{  
  7.         OutgoingSessionPromise.getInstance().process(packet);  
  8.         routed = true;  
  9.      }  
  10.      return routed;  
  11. }  

在OutgoingSessionPromise 中保有一个线程池和一个独立线程。

独立线程不断从消息队列中读取要处理的packet,并针对每个domain建立一个PacketsProcessor线程,将消息交给这个线程,然后把此线程放入线程池中运行。

Java代码 
  1. final Packet packet = packets.take();  
  2. boolean newProcessor = false;  
  3. PacketsProcessor packetsProcessor;  
  4. String domain = packet.getTo().getDomain();  
  5. synchronized (domain.intern()){  
  6.     packetsProcessor = packetsProcessors.get(domain);  
  7.     if(packetsProcessor == null){  
  8.        packetsProcessor = new PacketsProcessor(OutgoingSessionPromise.this,domain);  
  9.        packetsProcessors.put(domain,packetsProcessor);  
  10.        newProcessor = true;  
  11.     }  
  12.     packetsProcessor.addPacket(packet);  
  13. }  
  14. if(newProcessor){  
  15.    threadPool.execute(packetsProcessor);  
  16. }  

PacketsProcessor在发送消息包时会判断到外部服务器的连接是否已经建立。未建立的情况下会调用LocalOutgoingDServerSession.authenticateDomain() 方法建立连接。

具体的Socket连接建立是在authenticateDomain() 方法中经过一系列的验证和鉴权后调用createOutgoingSession(domain,hostname,port)来完成。

建立好连接后则重新调用routingTable.routePacket() 再进行一次路由。

------------------------------------------------------注意----------------------------------------------------

Openfire 中S2S 之间的链接有TLS 和 Dialback 两种加密验证方式。

如果使用TLS 方式则需要双方都有可信任的根证书,否则会出现General SSLEngine problem 异常。

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

另:Openfire 3.7.0 中的Dialback 方式有bug 会导致连接失败,已经在3.7.1中进行了修复。具体需要参照3.7.1中的代码修改LocalIncomingServerSession.java 和ServerDialback.java 两个文件。

原文地址:https://www.cnblogs.com/ilahsa/p/2680090.html