PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/dumbhippo/tags/pre-data-model-stacker/openfire/src/java/org/jivesoftware/openfire/stun/STUNService.java

https://gitlab.com/manoj-makkuboy/magnetism
Java | 430 lines | 296 code | 54 blank | 80 comment | 54 complexity | 55d5c27ddf0a21b42052b57bca9cb4b3 MD5 | raw file
  1. /**
  2. * Copyright (C) 2007 Jive Software. All rights reserved.
  3. *
  4. * This software is published under the terms of the GNU Public License (GPL),
  5. * a copy of which is included in this distribution.
  6. */
  7. package org.jivesoftware.openfire.stun;
  8. import de.javawi.jstun.test.demo.StunServer;
  9. import org.dom4j.Element;
  10. import org.jivesoftware.util.JiveGlobals;
  11. import org.jivesoftware.util.Log;
  12. import org.jivesoftware.util.PropertyEventDispatcher;
  13. import org.jivesoftware.util.PropertyEventListener;
  14. import org.jivesoftware.openfire.*;
  15. import org.jivesoftware.openfire.handler.IQHandler;
  16. import org.jivesoftware.openfire.auth.UnauthorizedException;
  17. import org.jivesoftware.openfire.container.BasicModule;
  18. import org.xmpp.packet.IQ;
  19. import org.xmpp.packet.PacketError;
  20. import java.net.InetAddress;
  21. import java.net.NetworkInterface;
  22. import java.net.SocketException;
  23. import java.net.UnknownHostException;
  24. import java.util.*;
  25. /**
  26. * STUN server and service module. It provides address discovery for p2p sessions to be
  27. * used for media transmission and receiving of UDP packets. It's especially useful for
  28. * clients behind NAT devices.
  29. *
  30. * @author Thiago Camargo
  31. */
  32. public class STUNService extends BasicModule {
  33. private static final String ELEMENT_NAME = "stun";
  34. private static final String NAMESPACE = "google:jingleinfo";
  35. private static final String DEFAULT_EXTERNAL_ADDRESSES =
  36. "stun.xten.net:3478;" +
  37. "jivesoftware.com:3478;" +
  38. "igniterealtime.org:3478;" +
  39. "stun.fwdnet.net:3478";
  40. private IQHandler stunIQHandler;
  41. private StunServer stunServer = null;
  42. private boolean enabled = false;
  43. private boolean localEnabled = false;
  44. private String primaryAddress = null;
  45. private String secondaryAddress = null;
  46. private int primaryPort;
  47. private int secondaryPort;
  48. private List<StunServerAddress> externalServers = null;
  49. /**
  50. * Constructs a new STUN Service
  51. */
  52. public STUNService() {
  53. super("STUN Service");
  54. }
  55. public void destroy() {
  56. super.destroy();
  57. stunServer = null;
  58. }
  59. public void initialize(XMPPServer server) {
  60. super.initialize(server);
  61. this.enabled = JiveGlobals.getBooleanProperty("stun.enabled", true);
  62. primaryAddress = JiveGlobals.getProperty("stun.address.primary");
  63. secondaryAddress = JiveGlobals.getProperty("stun.address.secondary");
  64. String addresses = JiveGlobals.getProperty("stun.external.addresses");
  65. // If no custom external addresses are defined, use the defaults.
  66. if (addresses == null) {
  67. addresses = DEFAULT_EXTERNAL_ADDRESSES;
  68. }
  69. externalServers = getStunServerAddresses(addresses);
  70. primaryPort = JiveGlobals.getIntProperty("stun.port.primary", 3478);
  71. secondaryPort = JiveGlobals.getIntProperty("stun.port.secondary", 3479);
  72. this.localEnabled = JiveGlobals.getBooleanProperty("stun.local.enabled", false);
  73. // If the local server is supposed to be enabled, ensure that primary and secondary
  74. // addresses are defined.
  75. if (localEnabled) {
  76. if (primaryAddress == null || secondaryAddress == null) {
  77. Log.warn("STUN server cannot be enabled. Primary and secondary addresses must be defined.");
  78. localEnabled = false;
  79. }
  80. }
  81. // Add listeners for STUN service being enabled and disabled via manual property changes.
  82. PropertyEventDispatcher.addListener(new PropertyEventListener() {
  83. public void propertySet(String property, Map<String, Object> params) {
  84. if (property.equals("stun.enabled")) {
  85. boolean oldValue = enabled;
  86. enabled = JiveGlobals.getBooleanProperty("stun.enabled", true);
  87. //
  88. if (enabled && !oldValue) {
  89. startSTUNService();
  90. } else if (!enabled && oldValue) {
  91. stop();
  92. }
  93. } else if (property.equals("stun.local.enabled")) {
  94. localEnabled = JiveGlobals.getBooleanProperty("stun.local.enabled", false);
  95. }
  96. }
  97. public void propertyDeleted(String property, Map<String, Object> params) {
  98. if (property.equals("stun.enabled")) {
  99. enabled = true;
  100. } else if (property.equals("stun.local.enabled")) {
  101. localEnabled = false;
  102. }
  103. }
  104. public void xmlPropertySet(String property, Map<String, Object> params) {
  105. // Ignore.
  106. }
  107. public void xmlPropertyDeleted(String property, Map<String, Object> params) {
  108. // Ignore.
  109. }
  110. });
  111. }
  112. public void start() {
  113. if (isEnabled()) {
  114. startSTUNService();
  115. if (isLocalEnabled()) {
  116. startLocalServer();
  117. }
  118. }
  119. }
  120. private void startLocalServer() {
  121. try {
  122. InetAddress primary = InetAddress.getByName(primaryAddress);
  123. InetAddress secondary = InetAddress.getByName(secondaryAddress);
  124. if (primary != null && secondary != null) {
  125. stunServer = new StunServer(primaryPort, primary, secondaryPort, secondary);
  126. stunServer.start();
  127. } else {
  128. setLocalEnabled(false);
  129. }
  130. }
  131. catch (SocketException e) {
  132. Log.error("Disabling STUN server", e);
  133. setLocalEnabled(false);
  134. }
  135. catch (UnknownHostException e) {
  136. Log.error("Disabling STUN server", e);
  137. setLocalEnabled(false);
  138. }
  139. }
  140. private void startSTUNService() {
  141. XMPPServer server = XMPPServer.getInstance();
  142. // Register the STUN feature in disco.
  143. server.getIQDiscoInfoHandler().addServerFeature(NAMESPACE);
  144. // Add an IQ handler.
  145. stunIQHandler = new STUNIQHandler();
  146. server.getIQRouter().addHandler(stunIQHandler);
  147. }
  148. private void stopSTUNService() {
  149. XMPPServer server = XMPPServer.getInstance();
  150. server.getIQDiscoInfoHandler().removeServerFeature(NAMESPACE);
  151. if (stunIQHandler != null) {
  152. server.getIQRouter().removeHandler(stunIQHandler);
  153. stunIQHandler = null;
  154. }
  155. }
  156. public void stop() {
  157. super.stop();
  158. this.enabled = false;
  159. stopSTUNService();
  160. stopLocal();
  161. }
  162. private void stopLocal() {
  163. if (stunServer != null) {
  164. stunServer.stop();
  165. }
  166. stunServer = null;
  167. }
  168. public String getName() {
  169. return "stun";
  170. }
  171. public List<StunServerAddress> getExternalServers() {
  172. return externalServers;
  173. }
  174. public void addExternalServer(String server, String port) {
  175. externalServers.add(new StunServerAddress(server, port));
  176. String property = "";
  177. for (StunServerAddress stunServerAddress : externalServers) {
  178. if (!property.equals("")) {
  179. property += ";";
  180. }
  181. property += stunServerAddress.getServer() + ":" + stunServerAddress.getPort();
  182. }
  183. JiveGlobals.setProperty("stun.external.addresses", property);
  184. }
  185. public void removeExternalServer(int index) {
  186. externalServers.remove(index);
  187. String property = "";
  188. for (StunServerAddress stunServerAddress : externalServers) {
  189. if (!property.equals("")) {
  190. property += ";";
  191. }
  192. property += stunServerAddress.getServer() + ":" + stunServerAddress.getPort();
  193. }
  194. JiveGlobals.setProperty("stun.external.addresses", property);
  195. }
  196. /**
  197. * Returns true if the service is enabled.
  198. *
  199. * @return enabled
  200. */
  201. public boolean isEnabled() {
  202. return enabled;
  203. }
  204. /**
  205. * Returns true if the local STUN server is enabled.
  206. *
  207. * @return enabled
  208. */
  209. public boolean isLocalEnabled() {
  210. return localEnabled;
  211. }
  212. /**
  213. * Set the service enable status.
  214. *
  215. * @param enabled boolean to enable or disable
  216. * @param localEnabled local Server enable or disable
  217. */
  218. public void setEnabled(boolean enabled, boolean localEnabled) {
  219. if (enabled && !this.enabled) {
  220. startSTUNService();
  221. if (isLocalEnabled()) {
  222. startLocalServer();
  223. }
  224. } else {
  225. stopSTUNService();
  226. }
  227. this.enabled = enabled;
  228. this.localEnabled = localEnabled;
  229. }
  230. /**
  231. * Set the Local STUN Server enable status.
  232. *
  233. * @param enabled boolean to enable or disable
  234. */
  235. public void setLocalEnabled(boolean enabled) {
  236. this.localEnabled = enabled;
  237. if (isLocalEnabled()) {
  238. startLocalServer();
  239. } else {
  240. stopLocal();
  241. }
  242. }
  243. /**
  244. * Get the secondary Port used by the STUN server
  245. *
  246. * @return secondary Port used by the STUN server
  247. */
  248. public int getSecondaryPort() {
  249. return secondaryPort;
  250. }
  251. /**
  252. * Get the primary Port used by the STUN server
  253. *
  254. * @return primary Port used by the STUN server
  255. */
  256. public int getPrimaryPort() {
  257. return primaryPort;
  258. }
  259. /**
  260. * Get the secondary Address used by the STUN server
  261. *
  262. * @return secondary Address used by the STUN server
  263. */
  264. public String getSecondaryAddress() {
  265. return secondaryAddress;
  266. }
  267. /**
  268. * Get the primary Address used by the STUN server
  269. *
  270. * @return primary Address used by the STUN server
  271. */
  272. public String getPrimaryAddress() {
  273. return primaryAddress;
  274. }
  275. public List<InetAddress> getAddresses() {
  276. List<InetAddress> list = new ArrayList<InetAddress>();
  277. try {
  278. Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
  279. while (ifaces.hasMoreElements()) {
  280. NetworkInterface iface = ifaces.nextElement();
  281. Enumeration<InetAddress> iaddresses = iface.getInetAddresses();
  282. while (iaddresses.hasMoreElements()) {
  283. InetAddress iaddress = iaddresses.nextElement();
  284. if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress()) {
  285. list.add(iaddress);
  286. }
  287. }
  288. }
  289. }
  290. catch (Exception e) {
  291. // Do Nothing
  292. }
  293. return list;
  294. }
  295. /**
  296. * Abstraction method used to convert a String into a STUN Server Address List
  297. *
  298. * @param addresses the String representation of server addresses with their
  299. * respective ports (server1:port1;server2:port2).
  300. * @return STUN server addresses list.
  301. */
  302. private List<StunServerAddress> getStunServerAddresses(String addresses) {
  303. List<StunServerAddress> list = new ArrayList<StunServerAddress>();
  304. if (addresses.equals("")) {
  305. return list;
  306. }
  307. String servers[] = addresses.split(";");
  308. for (String server : servers) {
  309. String address[] = server.split(":");
  310. StunServerAddress aux = new StunServerAddress(address[0], address[1]);
  311. if (!list.contains(aux)) {
  312. list.add(aux);
  313. }
  314. }
  315. return list;
  316. }
  317. /**
  318. * An IQ handler for STUN requests.
  319. */
  320. private class STUNIQHandler extends IQHandler {
  321. public STUNIQHandler() {
  322. super("stun");
  323. }
  324. public IQ handleIQ(IQ iq) throws UnauthorizedException {
  325. IQ reply = IQ.createResultIQ(iq);
  326. Element childElement = iq.getChildElement();
  327. String namespace = childElement.getNamespaceURI();
  328. Element childElementCopy = iq.getChildElement().createCopy();
  329. reply.setChildElement(childElementCopy);
  330. if (NAMESPACE.equals(namespace)) {
  331. if (isEnabled()) {
  332. Element stun = childElementCopy.addElement("stun");
  333. // If the local server is configured as a STUN server, send it as the first item.
  334. if (isLocalEnabled()) {
  335. StunServerAddress local;
  336. local = new StunServerAddress(primaryAddress, String.valueOf(primaryPort));
  337. if (!externalServers.contains(local)) {
  338. Element server = stun.addElement("server");
  339. server.addAttribute("host", local.getServer());
  340. server.addAttribute("udp", local.getPort());
  341. }
  342. }
  343. // Add any external STUN servers that are specified.
  344. for (StunServerAddress stunServerAddress : externalServers) {
  345. Element server = stun.addElement("server");
  346. server.addAttribute("host", stunServerAddress.getServer());
  347. server.addAttribute("udp", stunServerAddress.getPort());
  348. }
  349. try {
  350. String ip = sessionManager.getSession(iq.getFrom()).getConnection().getInetAddress().getHostAddress();
  351. if (ip != null) {
  352. Element publicIp = childElementCopy.addElement("publicip");
  353. publicIp.addAttribute("ip", ip);
  354. }
  355. }
  356. catch (UnknownHostException e) {
  357. e.printStackTrace();
  358. }
  359. }
  360. } else {
  361. // Answer an error since the server can't handle the requested namespace
  362. reply.setError(PacketError.Condition.service_unavailable);
  363. }
  364. try {
  365. Log.debug("RETURNED:" + reply.toXML());
  366. }
  367. catch (Exception e) {
  368. Log.error(e);
  369. }
  370. return reply;
  371. }
  372. public IQHandlerInfo getInfo() {
  373. return new IQHandlerInfo(ELEMENT_NAME, NAMESPACE);
  374. }
  375. }
  376. }