发送给其它服务器的消息由@domain 部分区分,在进入到服务器路由后在RoutingTableImpl.routePacket(Packet packet) 中与发送给本地服务器的消息分离。
public void routePacket(JID jid,......){
boolean routed = false;
if(serverName.equals(jid.getDomain())){
routed = routeToLocalDomain(jid,packet,fromServer);
}
else if(jid.getDomain().contains(serverName)){
routed = routeToComponent(jid,packet,routed);
}
else{
routed = routeToRemoteDomain(jid,packet,routed);
}
}
......
在初次发送消息给外部服务器时两台服务器的连接还没有建立,这种情况下会将包交由一个OutgoingSessionPromise 对象来处理,将消息加入它的队列。
private boolean routeToRomoteDomain(JID jid,Packet packet,boolean routed){
byte[] nodeID = serverCache.get(jid.getDomain);
if(nodeID!=null){
......
}
else{
OutgoingSessionPromise.getInstance().process(packet);
routed = true;
}
return routed;
}
在OutgoingSessionPromise 中保有一个线程池和一个独立线程。
独立线程不断从消息队列中读取要处理的packet,并针对每个domain建立一个PacketsProcessor线程,将消息交给这个线程,然后把此线程放入线程池中运行。
final Packet packet = packets.take();
boolean newProcessor = false;
PacketsProcessor packetsProcessor;
String domain = packet.getTo().getDomain();
synchronized (domain.intern()){
packetsProcessor = packetsProcessors.get(domain);
if(packetsProcessor == null){
packetsProcessor = new PacketsProcessor(OutgoingSessionPromise.this,domain);
packetsProcessors.put(domain,packetsProcessor);
newProcessor = true;
}
packetsProcessor.addPacket(packet);
}
if(newProcessor){
threadPool.execute(packetsProcessor);
}
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 两个文件。