GridInfo.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Net;
  30. using System.Reflection;
  31. using log4net;
  32. using Nini.Config;
  33. namespace OpenSim.Framework
  34. {
  35. public enum OSHTTPURIFlags : byte
  36. {
  37. None = 0,
  38. ValidHost = 1,
  39. Resolved = 1 << 1,
  40. ValidResolved = ValidHost | Resolved
  41. }
  42. // full http or https schema, server host, port and possible server path any query is ignored.
  43. public struct OSHTTPURI:IComparable<OSHTTPURI>, IEquatable<OSHTTPURI>
  44. {
  45. public OSHTTPURIFlags Flags;
  46. public int Port;
  47. public IPAddress IP;
  48. public readonly string Host;
  49. public readonly string URL;
  50. public readonly string Path;
  51. public readonly string URI;
  52. public OSHTTPURI(string uri, bool withDNSResolve = false)
  53. {
  54. Flags = OSHTTPURIFlags.None;
  55. Port = -1;
  56. IP = null;
  57. Host = string.Empty;
  58. URI = string.Empty;
  59. URL = string.Empty;
  60. Path = string.Empty;
  61. if (string.IsNullOrEmpty(uri))
  62. return;
  63. try
  64. {
  65. Uri m_checkuri = new Uri(uri);
  66. if(m_checkuri.Scheme != Uri.UriSchemeHttp && m_checkuri.Scheme != Uri.UriSchemeHttps)
  67. return;
  68. Flags = OSHTTPURIFlags.ValidHost;
  69. Host = m_checkuri.DnsSafeHost.ToLowerInvariant();
  70. Port = m_checkuri.Port;
  71. Path = m_checkuri.AbsolutePath;
  72. if (Path[Path.Length - 1] == '/')
  73. Path = Path.Substring(0, Path.Length - 1);
  74. URL = m_checkuri.Scheme + "://" + Host + ":" + Port;
  75. URI = URL + Path;
  76. if (withDNSResolve)
  77. {
  78. IPAddress ip = Util.GetHostFromDNS(Host);
  79. if (ip != null)
  80. {
  81. IP = ip;
  82. Flags = OSHTTPURIFlags.ValidResolved;
  83. }
  84. }
  85. }
  86. catch
  87. {
  88. Flags = OSHTTPURIFlags.None;
  89. IP = null;
  90. URI = string.Empty;
  91. }
  92. }
  93. public bool ResolveDNS()
  94. {
  95. IPAddress ip = Util.GetHostFromDNS(Host);
  96. if (ip == null)
  97. {
  98. Flags &= ~OSHTTPURIFlags.Resolved;
  99. return false;
  100. }
  101. Flags |= OSHTTPURIFlags.Resolved;
  102. return true;
  103. }
  104. public bool IsValidHost
  105. {
  106. get { return Flags != OSHTTPURIFlags.None;}
  107. }
  108. public bool ValidAndResolved(out string error)
  109. {
  110. if (Flags == OSHTTPURIFlags.None)
  111. {
  112. error = "failed to parse uri";
  113. return false;
  114. }
  115. if ((Flags & OSHTTPURIFlags.Resolved) == 0)
  116. {
  117. error = "failed DNS resolve of uri host";
  118. return false;
  119. }
  120. error = string.Empty;
  121. return true;
  122. }
  123. public bool IsResolvedHost
  124. {
  125. get {return (Flags & OSHTTPURIFlags.Resolved) != 0; }
  126. }
  127. public string URIwEndSlash
  128. {
  129. get { return Flags != OSHTTPURIFlags.None ? "" : URI + "/";}
  130. }
  131. public int CompareTo(OSHTTPURI other)
  132. {
  133. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  134. {
  135. if (Path.Equals(other.Path))
  136. return Host.CompareTo(other.Host);
  137. }
  138. return -1;
  139. }
  140. public bool Equals(OSHTTPURI other)
  141. {
  142. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  143. {
  144. if (Path.Equals(other.Path))
  145. return Host.Equals(other.Host);
  146. }
  147. return false;
  148. }
  149. public override int GetHashCode()
  150. {
  151. return URI.GetHashCode();
  152. }
  153. }
  154. //host and port. Can not have server internal path or query. http scheme is assumed if not present
  155. public struct OSHHTPHost : IComparable<OSHHTPHost>, IEquatable<OSHHTPHost>
  156. {
  157. public OSHTTPURIFlags Flags;
  158. public int Port;
  159. public IPAddress IP;
  160. public readonly string Host;
  161. public readonly string URI;
  162. public OSHHTPHost(string url, bool withDNSResolve = false)
  163. {
  164. Flags = OSHTTPURIFlags.None;
  165. Port = 80;
  166. IP = null;
  167. Host = string.Empty;
  168. URI = string.Empty;
  169. bool secureHTTP = false;
  170. if (string.IsNullOrEmpty(url))
  171. return;
  172. url = url.ToLowerInvariant();
  173. try
  174. {
  175. int urllen = url.Length;
  176. if (url[urllen - 1] == '/')
  177. --urllen;
  178. int start;
  179. if (url.StartsWith("http"))
  180. {
  181. if (url[4] == 's')
  182. {
  183. start = 8;
  184. secureHTTP = true;
  185. }
  186. else
  187. start = 7;
  188. }
  189. else
  190. start = 0;
  191. string host;
  192. UriHostNameType type;
  193. int indx = url.IndexOf(':', start, urllen - start);
  194. if (indx > 0)
  195. {
  196. host = url.Substring(start, indx - start);
  197. type = Uri.CheckHostName(host);
  198. if (type == UriHostNameType.Unknown || type == UriHostNameType.Basic)
  199. return;
  200. ++indx;
  201. string sport = url.Substring(indx, urllen - indx);
  202. int tmp;
  203. if (!int.TryParse(sport, out tmp) || tmp < 0 || tmp > 65535)
  204. return;
  205. Flags = OSHTTPURIFlags.ValidHost;
  206. Host = host;
  207. Port = tmp;
  208. URI = (secureHTTP ? "https://" : "http://") + Host + ":" + Port.ToString();
  209. }
  210. else
  211. {
  212. host = url.Substring(start, urllen - start);
  213. type = Uri.CheckHostName(host);
  214. if (type == UriHostNameType.Unknown || type == UriHostNameType.Basic)
  215. return;
  216. Flags = OSHTTPURIFlags.ValidHost;
  217. Host = host;
  218. if (secureHTTP)
  219. {
  220. Port = 443;
  221. URI = "https://" + Host + ":443";
  222. }
  223. else
  224. {
  225. Port = 80;
  226. URI = "http://" + Host + ":80";
  227. }
  228. }
  229. if (withDNSResolve)
  230. {
  231. IPAddress ip = Util.GetHostFromDNS(host);
  232. if (ip != null)
  233. {
  234. Flags = OSHTTPURIFlags.ValidResolved;
  235. IP = ip;
  236. }
  237. }
  238. }
  239. catch
  240. {
  241. Flags = OSHTTPURIFlags.None;
  242. IP = null;
  243. URI = string.Empty;
  244. }
  245. }
  246. public bool ResolveDNS()
  247. {
  248. IPAddress ip = Util.GetHostFromDNS(Host);
  249. if (ip == null)
  250. {
  251. Flags &= ~OSHTTPURIFlags.Resolved;
  252. return false;
  253. }
  254. Flags |= OSHTTPURIFlags.Resolved;
  255. return true;
  256. }
  257. public bool IsValidHost
  258. {
  259. get { return Flags != OSHTTPURIFlags.None; }
  260. }
  261. public bool IsResolvedHost
  262. {
  263. get { return (Flags & OSHTTPURIFlags.Resolved) != 0; }
  264. }
  265. public bool ValidAndResolved(out string error)
  266. {
  267. if (Flags == OSHTTPURIFlags.None)
  268. {
  269. error = "failed to parse uri";
  270. return false;
  271. }
  272. if ((Flags & OSHTTPURIFlags.Resolved) == 0)
  273. {
  274. error = "failed DNS resolve of uri host";
  275. return false;
  276. }
  277. error = string.Empty;
  278. return true;
  279. }
  280. public string URIwEndSlash
  281. {
  282. get { return (Flags == OSHTTPURIFlags.None) ? "" : URI + "/"; }
  283. }
  284. public int CompareTo(OSHHTPHost other)
  285. {
  286. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  287. {
  288. return Host.CompareTo(other.Host);
  289. }
  290. return -1;
  291. }
  292. public bool Equals(OSHHTPHost other)
  293. {
  294. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  295. {
  296. return Host.Equals(other.Host);
  297. }
  298. return false;
  299. }
  300. public override int GetHashCode()
  301. {
  302. return URI.GetHashCode();
  303. }
  304. }
  305. public class GridInfo
  306. {
  307. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  308. private bool m_hasHGconfig;
  309. private OSHHTPHost m_gateKeeperURL;
  310. private HashSet<OSHHTPHost> m_gateKeeperAlias;
  311. private OSHHTPHost m_homeURL;
  312. private HashSet<OSHHTPHost> m_homeURLAlias;
  313. public GridInfo (IConfigSource config, string defaultURI = "")
  314. {
  315. string[] sections = new string[] { "Startup", "Hypergrid"};
  316. string gatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI", sections, String.Empty);
  317. if (string.IsNullOrEmpty(gatekeeper))
  318. {
  319. IConfig serverConfig = config.Configs["GatekeeperService"];
  320. if (serverConfig != null)
  321. gatekeeper = serverConfig.GetString("ExternalName", string.Empty);
  322. }
  323. if (string.IsNullOrEmpty(gatekeeper))
  324. {
  325. IConfig gridConfig = config.Configs["GridService"];
  326. if (gridConfig != null)
  327. gatekeeper = gridConfig.GetString("Gatekeeper", string.Empty);
  328. }
  329. if (string.IsNullOrEmpty(gatekeeper))
  330. {
  331. m_hasHGconfig = false;
  332. if (!string.IsNullOrEmpty(defaultURI))
  333. m_gateKeeperURL = new OSHHTPHost(defaultURI, true);
  334. }
  335. else
  336. {
  337. m_gateKeeperURL = new OSHHTPHost(gatekeeper, true);
  338. m_hasHGconfig = true;
  339. }
  340. if (!m_gateKeeperURL.IsResolvedHost)
  341. {
  342. m_log.Error(m_gateKeeperURL.IsValidHost ? "Could not resolve GatekeeperURI" : "GatekeeperURI is a invalid host");
  343. throw new Exception("GatekeeperURI configuration error");
  344. }
  345. string gatekeeperURIAlias = Util.GetConfigVarFromSections<string>(config, "GatekeeperURIAlias", sections, String.Empty);
  346. if (!string.IsNullOrWhiteSpace(gatekeeperURIAlias))
  347. {
  348. string[] alias = gatekeeperURIAlias.Split(',');
  349. for (int i = 0; i < alias.Length; ++i)
  350. {
  351. OSHHTPHost tmp = new OSHHTPHost(alias[i].Trim(), false);
  352. if (tmp.IsValidHost)
  353. {
  354. if (m_gateKeeperAlias == null)
  355. m_gateKeeperAlias = new HashSet<OSHHTPHost>();
  356. m_gateKeeperAlias.Add(tmp);
  357. }
  358. }
  359. }
  360. string home = Util.GetConfigVarFromSections<string>(config, "HomeURI", sections, string.Empty);
  361. if (string.IsNullOrEmpty(home))
  362. {
  363. if (!string.IsNullOrEmpty(gatekeeper))
  364. m_homeURL = m_gateKeeperURL;
  365. else if (!string.IsNullOrEmpty(defaultURI))
  366. m_homeURL = new OSHHTPHost(defaultURI, true);
  367. }
  368. else
  369. m_homeURL = new OSHHTPHost(home, true);
  370. if (!m_homeURL.IsResolvedHost)
  371. {
  372. m_log.Error(m_homeURL.IsValidHost ? "Could not resolve HomeURI" : "HomeURI is a invalid host");
  373. throw new Exception("HomeURI configuration error");
  374. }
  375. string homeAlias = Util.GetConfigVarFromSections<string>(config, "HomeURIAlias", sections, String.Empty);
  376. if (!string.IsNullOrWhiteSpace(homeAlias))
  377. {
  378. string[] alias = homeAlias.Split(',');
  379. for (int i = 0; i < alias.Length; ++i)
  380. {
  381. OSHHTPHost tmp = new OSHHTPHost(alias[i].Trim(), false);
  382. if (tmp.IsValidHost)
  383. {
  384. if (m_homeURLAlias == null)
  385. m_homeURLAlias = new HashSet<OSHHTPHost>();
  386. m_homeURLAlias.Add(tmp);
  387. }
  388. }
  389. }
  390. }
  391. public bool HasHGConfig
  392. {
  393. get { return m_hasHGconfig; }
  394. }
  395. public string GateKeeperURL
  396. {
  397. get { return m_gateKeeperURL.URIwEndSlash; }
  398. }
  399. public string GateKeeperURLNoEndSlash
  400. {
  401. get { return m_gateKeeperURL.URI; }
  402. }
  403. public string HGGateKeeperURL
  404. {
  405. get
  406. {
  407. if (m_hasHGconfig)
  408. return m_gateKeeperURL.URIwEndSlash;
  409. return string.Empty;
  410. }
  411. }
  412. public string HGGateKeeperURLNoEndSlash
  413. {
  414. get
  415. {
  416. if (m_hasHGconfig)
  417. return m_gateKeeperURL.URI;
  418. return string.Empty;
  419. }
  420. }
  421. public string HomeURL
  422. {
  423. get { return m_homeURL.URIwEndSlash; }
  424. }
  425. public string HomeURLNoEndSlash
  426. {
  427. get { return m_homeURL.URI; }
  428. }
  429. public string HGHomeURL
  430. {
  431. get
  432. {
  433. if (m_hasHGconfig)
  434. return m_homeURL.URIwEndSlash;
  435. return string.Empty;
  436. }
  437. }
  438. public string HGHomeURLNoEndSlash
  439. {
  440. get
  441. {
  442. if (m_hasHGconfig)
  443. return m_homeURL.URI;
  444. return string.Empty;
  445. }
  446. }
  447. // -2 dns failed
  448. // -1 if bad url
  449. // 0 if not local
  450. // 1 if local
  451. public int IsLocalGrid(string othergatekeeper)
  452. {
  453. OSHHTPHost tmp = new OSHHTPHost(othergatekeeper, false);
  454. if (!tmp.IsValidHost)
  455. return -1;
  456. if (tmp.Equals(m_gateKeeperURL))
  457. return 1;
  458. if (m_gateKeeperAlias != null && m_gateKeeperAlias.Contains(tmp))
  459. return 1;
  460. return 0;
  461. }
  462. public int IsLocalGrid(string othergatekeeper, bool withResolveCheck)
  463. {
  464. OSHHTPHost tmp = new OSHHTPHost(othergatekeeper, false);
  465. if (!tmp.IsValidHost)
  466. return -1;
  467. if (tmp.Equals(m_gateKeeperURL))
  468. return 1;
  469. if (m_gateKeeperAlias != null && m_gateKeeperAlias.Contains(tmp))
  470. return 1;
  471. if (withResolveCheck)
  472. {
  473. if (tmp.IsResolvedHost)
  474. return 0;
  475. return tmp.ResolveDNS() ? 0 : -2;
  476. }
  477. return 0;
  478. }
  479. public int IsLocalHome(string otherhome)
  480. {
  481. OSHHTPHost tmp = new OSHHTPHost(otherhome, false);
  482. if (!tmp.IsValidHost)
  483. return -1;
  484. if (tmp.Equals(m_homeURL))
  485. return 1;
  486. if (m_homeURLAlias != null && m_homeURLAlias.Contains(tmp))
  487. return 1;
  488. return 0;
  489. }
  490. public int IsLocalHome(string otherhome, bool withResolveCheck)
  491. {
  492. OSHHTPHost tmp = new OSHHTPHost(otherhome, false);
  493. if (!tmp.IsValidHost)
  494. return -1;
  495. if (tmp.Equals(m_homeURL))
  496. return 1;
  497. if (m_homeURLAlias != null && m_homeURLAlias.Contains(tmp))
  498. return 1;
  499. if (withResolveCheck)
  500. {
  501. if (tmp.IsResolvedHost)
  502. return 0;
  503. return tmp.ResolveDNS() ? 0 : -2;
  504. }
  505. return 0;
  506. }
  507. }
  508. }