GridInfo.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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 URI;
  50. public readonly string Path;
  51. public OSHTTPURI(string uri, bool withDNSResolve = false)
  52. {
  53. Flags = OSHTTPURIFlags.None;
  54. Port = -1;
  55. IP = null;
  56. Host = string.Empty;
  57. URI = string.Empty;
  58. Path = string.Empty;
  59. if (string.IsNullOrEmpty(uri))
  60. return;
  61. try
  62. {
  63. Uri m_checkuri = new Uri(uri);
  64. if(m_checkuri.Scheme != Uri.UriSchemeHttp && m_checkuri.Scheme != Uri.UriSchemeHttps)
  65. return;
  66. Flags = OSHTTPURIFlags.ValidHost;
  67. Host = m_checkuri.DnsSafeHost.ToLowerInvariant();
  68. Port = m_checkuri.Port;
  69. Path = m_checkuri.AbsolutePath;
  70. if (Path[Path.Length - 1] == '/')
  71. Path = Path.Substring(0, Path.Length - 1);
  72. URI = m_checkuri.Scheme + "://" + Host + ":" + Port + Path;
  73. if (withDNSResolve)
  74. {
  75. IPAddress ip = Util.GetHostFromDNS(Host);
  76. if (ip != null)
  77. {
  78. IP = ip;
  79. Flags = OSHTTPURIFlags.ValidResolved;
  80. }
  81. }
  82. }
  83. catch
  84. {
  85. Flags = OSHTTPURIFlags.None;
  86. IP = null;
  87. URI = string.Empty;
  88. }
  89. }
  90. public bool ResolveDNS()
  91. {
  92. IPAddress ip = Util.GetHostFromDNS(Host);
  93. if (ip == null)
  94. {
  95. Flags &= ~OSHTTPURIFlags.Resolved;
  96. return false;
  97. }
  98. Flags |= OSHTTPURIFlags.Resolved;
  99. return true;
  100. }
  101. public bool IsValidHost
  102. {
  103. get { return Flags != OSHTTPURIFlags.None;}
  104. }
  105. public bool ValidAndResolved(out string error)
  106. {
  107. if (Flags == OSHTTPURIFlags.None)
  108. {
  109. error = "failed to parse uri";
  110. return false;
  111. }
  112. if ((Flags & OSHTTPURIFlags.Resolved) == 0)
  113. {
  114. error = "failed DNS resolve of uri host";
  115. return false;
  116. }
  117. error = string.Empty;
  118. return true;
  119. }
  120. public bool IsResolvedHost
  121. {
  122. get {return (Flags & OSHTTPURIFlags.Resolved) != 0; }
  123. }
  124. public string URIwEndSlash
  125. {
  126. get { return Flags != OSHTTPURIFlags.None ? "" : URI + "/";}
  127. }
  128. public int CompareTo(OSHTTPURI other)
  129. {
  130. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  131. {
  132. if (Path.Equals(other.Path))
  133. return Host.CompareTo(other.Host);
  134. }
  135. return -1;
  136. }
  137. public bool Equals(OSHTTPURI other)
  138. {
  139. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  140. {
  141. if (Path.Equals(other.Path))
  142. return Host.Equals(other.Host);
  143. }
  144. return false;
  145. }
  146. public override int GetHashCode()
  147. {
  148. return URI.GetHashCode();
  149. }
  150. }
  151. //host and port. Can not have server internal path or query. http scheme is assumed if not present
  152. public struct OSHHTPHost : IComparable<OSHHTPHost>, IEquatable<OSHHTPHost>
  153. {
  154. public OSHTTPURIFlags Flags;
  155. public int Port;
  156. public IPAddress IP;
  157. public readonly string Host;
  158. public readonly string URI;
  159. public OSHHTPHost(string url, bool withDNSResolve = false)
  160. {
  161. Flags = OSHTTPURIFlags.None;
  162. Port = 80;
  163. IP = null;
  164. Host = string.Empty;
  165. URI = string.Empty;
  166. bool secureHTTP = false;
  167. if (string.IsNullOrEmpty(url))
  168. return;
  169. url = url.ToLowerInvariant();
  170. try
  171. {
  172. int urllen = url.Length;
  173. if (url[urllen - 1] == '/')
  174. --urllen;
  175. int start;
  176. if (url.StartsWith("http"))
  177. {
  178. if (url[4] == 's')
  179. {
  180. start = 8;
  181. secureHTTP = true;
  182. }
  183. else
  184. start = 7;
  185. }
  186. else
  187. start = 0;
  188. string host;
  189. UriHostNameType type;
  190. int indx = url.IndexOf(':', start, urllen - start);
  191. if (indx > 0)
  192. {
  193. host = url.Substring(start, indx - start);
  194. type = Uri.CheckHostName(host);
  195. if (type == UriHostNameType.Unknown || type == UriHostNameType.Basic)
  196. return;
  197. ++indx;
  198. string sport = url.Substring(indx, urllen - indx);
  199. int tmp;
  200. if (!int.TryParse(sport, out tmp) || tmp < 0 || tmp > 65535)
  201. return;
  202. Flags = OSHTTPURIFlags.ValidHost;
  203. Host = host;
  204. Port = tmp;
  205. URI = (secureHTTP ? "https://" : "http://") + Host + ":" + Port.ToString();
  206. }
  207. else
  208. {
  209. host = url.Substring(start, urllen - start);
  210. type = Uri.CheckHostName(host);
  211. if (type == UriHostNameType.Unknown || type == UriHostNameType.Basic)
  212. return;
  213. Flags = OSHTTPURIFlags.ValidHost;
  214. Host = host;
  215. if (secureHTTP)
  216. {
  217. Port = 443;
  218. URI = "https://" + Host + ":443";
  219. }
  220. else
  221. {
  222. Port = 80;
  223. URI = "http://" + Host + ":80";
  224. }
  225. }
  226. if (withDNSResolve)
  227. {
  228. IPAddress ip = Util.GetHostFromDNS(host);
  229. if (ip != null)
  230. {
  231. Flags = OSHTTPURIFlags.ValidResolved;
  232. IP = ip;
  233. }
  234. }
  235. }
  236. catch
  237. {
  238. Flags = OSHTTPURIFlags.None;
  239. IP = null;
  240. URI = string.Empty;
  241. }
  242. }
  243. public bool ResolveDNS()
  244. {
  245. IPAddress ip = Util.GetHostFromDNS(Host);
  246. if (ip == null)
  247. {
  248. Flags &= ~OSHTTPURIFlags.Resolved;
  249. return false;
  250. }
  251. Flags |= OSHTTPURIFlags.Resolved;
  252. return true;
  253. }
  254. public bool IsValidHost
  255. {
  256. get { return Flags != OSHTTPURIFlags.None; }
  257. }
  258. public bool IsResolvedHost
  259. {
  260. get { return (Flags & OSHTTPURIFlags.Resolved) != 0; }
  261. }
  262. public bool ValidAndResolved(out string error)
  263. {
  264. if (Flags == OSHTTPURIFlags.None)
  265. {
  266. error = "failed to parse uri";
  267. return false;
  268. }
  269. if ((Flags & OSHTTPURIFlags.Resolved) == 0)
  270. {
  271. error = "failed DNS resolve of uri host";
  272. return false;
  273. }
  274. error = string.Empty;
  275. return true;
  276. }
  277. public string URIwEndSlash
  278. {
  279. get { return (Flags == OSHTTPURIFlags.None) ? "" : URI + "/"; }
  280. }
  281. public int CompareTo(OSHHTPHost other)
  282. {
  283. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  284. {
  285. return Host.CompareTo(other.Host);
  286. }
  287. return -1;
  288. }
  289. public bool Equals(OSHHTPHost other)
  290. {
  291. if (Port == other.Port && ((Flags & other.Flags) & OSHTTPURIFlags.ValidHost) != 0)
  292. {
  293. return Host.Equals(other.Host);
  294. }
  295. return false;
  296. }
  297. public override int GetHashCode()
  298. {
  299. return URI.GetHashCode();
  300. }
  301. }
  302. public class GridInfo
  303. {
  304. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  305. private bool m_hasHGconfig;
  306. private OSHHTPHost m_gateKeeperURL;
  307. private HashSet<OSHHTPHost> m_gateKeeperAlias;
  308. private OSHHTPHost m_homeURL;
  309. private HashSet<OSHHTPHost> m_homeURLAlias;
  310. public GridInfo (IConfigSource config, string defaultURI = "")
  311. {
  312. string[] sections = new string[] { "Startup", "Hypergrid"};
  313. string gatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI", sections, String.Empty);
  314. if (string.IsNullOrEmpty(gatekeeper))
  315. {
  316. IConfig serverConfig = config.Configs["GatekeeperService"];
  317. if (serverConfig != null)
  318. gatekeeper = serverConfig.GetString("ExternalName", string.Empty);
  319. }
  320. if (string.IsNullOrEmpty(gatekeeper))
  321. {
  322. IConfig gridConfig = config.Configs["GridService"];
  323. if (gridConfig != null)
  324. gatekeeper = gridConfig.GetString("Gatekeeper", string.Empty);
  325. }
  326. if (string.IsNullOrEmpty(gatekeeper))
  327. {
  328. m_hasHGconfig = false;
  329. if (!string.IsNullOrEmpty(defaultURI))
  330. m_gateKeeperURL = new OSHHTPHost(defaultURI, true);
  331. }
  332. else
  333. {
  334. m_gateKeeperURL = new OSHHTPHost(gatekeeper, true);
  335. m_hasHGconfig = true;
  336. }
  337. if (!m_gateKeeperURL.IsResolvedHost)
  338. {
  339. m_log.Error(m_gateKeeperURL.IsValidHost ? "Could not resolve GatekeeperURI" : "GatekeeperURI is a invalid host");
  340. throw new Exception("GatekeeperURI configuration error");
  341. }
  342. string gatekeeperURIAlias = Util.GetConfigVarFromSections<string>(config, "GatekeeperURIAlias", sections, String.Empty);
  343. if (!string.IsNullOrWhiteSpace(gatekeeperURIAlias))
  344. {
  345. string[] alias = gatekeeperURIAlias.Split(',');
  346. for (int i = 0; i < alias.Length; ++i)
  347. {
  348. OSHHTPHost tmp = new OSHHTPHost(alias[i].Trim(), false);
  349. if (tmp.IsValidHost)
  350. {
  351. if (m_gateKeeperAlias == null)
  352. m_gateKeeperAlias = new HashSet<OSHHTPHost>();
  353. m_gateKeeperAlias.Add(tmp);
  354. }
  355. }
  356. }
  357. string home = Util.GetConfigVarFromSections<string>(config, "HomeURI", sections, string.Empty);
  358. if (string.IsNullOrEmpty(home))
  359. {
  360. if (!string.IsNullOrEmpty(gatekeeper))
  361. m_homeURL = m_gateKeeperURL;
  362. else if (!string.IsNullOrEmpty(defaultURI))
  363. m_homeURL = new OSHHTPHost(defaultURI, true);
  364. }
  365. else
  366. m_homeURL = new OSHHTPHost(home, true);
  367. if (!m_homeURL.IsResolvedHost)
  368. {
  369. m_log.Error(m_homeURL.IsValidHost ? "Could not resolve HomeURI" : "HomeURI is a invalid host");
  370. throw new Exception("HomeURI configuration error");
  371. }
  372. string homeAlias = Util.GetConfigVarFromSections<string>(config, "HomeURIAlias", sections, String.Empty);
  373. if (!string.IsNullOrWhiteSpace(homeAlias))
  374. {
  375. string[] alias = homeAlias.Split(',');
  376. for (int i = 0; i < alias.Length; ++i)
  377. {
  378. OSHHTPHost tmp = new OSHHTPHost(alias[i].Trim(), false);
  379. if (tmp.IsValidHost)
  380. {
  381. if (m_homeURLAlias == null)
  382. m_homeURLAlias = new HashSet<OSHHTPHost>();
  383. m_homeURLAlias.Add(tmp);
  384. }
  385. }
  386. }
  387. }
  388. public bool HasHGConfig
  389. {
  390. get { return m_hasHGconfig; }
  391. }
  392. public string GateKeeperURL
  393. {
  394. get { return m_gateKeeperURL.URIwEndSlash; }
  395. }
  396. public string GateKeeperURLNoEndSlash
  397. {
  398. get { return m_gateKeeperURL.URI; }
  399. }
  400. public string HGGateKeeperURL
  401. {
  402. get
  403. {
  404. if (m_hasHGconfig)
  405. return m_gateKeeperURL.URIwEndSlash;
  406. return string.Empty;
  407. }
  408. }
  409. public string HGGateKeeperURLNoEndSlash
  410. {
  411. get
  412. {
  413. if (m_hasHGconfig)
  414. return m_gateKeeperURL.URI;
  415. return string.Empty;
  416. }
  417. }
  418. public string HomeURL
  419. {
  420. get { return m_homeURL.URIwEndSlash; }
  421. }
  422. public string HomeURLNoEndSlash
  423. {
  424. get { return m_homeURL.URI; }
  425. }
  426. public string HGHomeURL
  427. {
  428. get
  429. {
  430. if (m_hasHGconfig)
  431. return m_homeURL.URIwEndSlash;
  432. return string.Empty;
  433. }
  434. }
  435. public string HGHomeURLNoEndSlash
  436. {
  437. get
  438. {
  439. if (m_hasHGconfig)
  440. return m_homeURL.URI;
  441. return string.Empty;
  442. }
  443. }
  444. // -2 dns failed
  445. // -1 if bad url
  446. // 0 if not local
  447. // 1 if local
  448. public int IsLocalGrid(string othergatekeeper)
  449. {
  450. OSHHTPHost tmp = new OSHHTPHost(othergatekeeper, false);
  451. if (!tmp.IsValidHost)
  452. return -1;
  453. if (tmp.Equals(m_gateKeeperURL))
  454. return 1;
  455. if (m_gateKeeperAlias != null && m_gateKeeperAlias.Contains(tmp))
  456. return 1;
  457. return 0;
  458. }
  459. public int IsLocalGrid(string othergatekeeper, bool withResolveCheck)
  460. {
  461. OSHHTPHost tmp = new OSHHTPHost(othergatekeeper, false);
  462. if (!tmp.IsValidHost)
  463. return -1;
  464. if (tmp.Equals(m_gateKeeperURL))
  465. return 1;
  466. if (m_gateKeeperAlias != null && m_gateKeeperAlias.Contains(tmp))
  467. return 1;
  468. if (withResolveCheck)
  469. {
  470. if (tmp.IsResolvedHost)
  471. return 0;
  472. return tmp.ResolveDNS() ? 0 : -2;
  473. }
  474. return 0;
  475. }
  476. public int IsLocalHome(string otherhome)
  477. {
  478. OSHHTPHost tmp = new OSHHTPHost(otherhome, false);
  479. if (!tmp.IsValidHost)
  480. return -1;
  481. if (tmp.Equals(m_homeURL))
  482. return 1;
  483. if (m_homeURLAlias != null && m_homeURLAlias.Contains(tmp))
  484. return 1;
  485. return 0;
  486. }
  487. public int IsLocalHome(string otherhome, bool withResolveCheck)
  488. {
  489. OSHHTPHost tmp = new OSHHTPHost(otherhome, false);
  490. if (!tmp.IsValidHost)
  491. return -1;
  492. if (tmp.Equals(m_homeURL))
  493. return 1;
  494. if (m_homeURLAlias != null && m_homeURLAlias.Contains(tmp))
  495. return 1;
  496. if (withResolveCheck)
  497. {
  498. if (tmp.IsResolvedHost)
  499. return 0;
  500. return tmp.ResolveDNS() ? 0 : -2;
  501. }
  502. return 0;
  503. }
  504. }
  505. }