clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Linq;
32 using System.Net;
33 using System.Reflection;
34 using System.Text.RegularExpressions;
35  
36 using log4net;
37 using Nini.Config;
38 using OpenMetaverse;
39  
40 using OpenSim.Framework;
41 using OpenSim.Framework.Console;
42 using OpenSim.Server.Base;
43 using OpenSim.Services.Interfaces;
44 using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45 using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
46 using OpenSim.Services.Connectors.Hypergrid;
47  
48 namespace OpenSim.Services.LLLoginService
49 {
50 public class LLLoginService : ILoginService
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 private static readonly string LogHeader = "[LLOGIN SERVICE]";
54  
55 private static bool Initialized = false;
56  
57 protected IUserAccountService m_UserAccountService;
58 protected IGridUserService m_GridUserService;
59 protected IAuthenticationService m_AuthenticationService;
60 protected IInventoryService m_InventoryService;
61 protected IInventoryService m_HGInventoryService;
62 protected IGridService m_GridService;
63 protected IPresenceService m_PresenceService;
64 protected ISimulationService m_LocalSimulationService;
65 protected ISimulationService m_RemoteSimulationService;
66 protected ILibraryService m_LibraryService;
67 protected IFriendsService m_FriendsService;
68 protected IAvatarService m_AvatarService;
69 protected IUserAgentService m_UserAgentService;
70  
71 protected GatekeeperServiceConnector m_GatekeeperConnector;
72  
73 protected string m_DefaultRegionName;
74 protected string m_WelcomeMessage;
75 protected bool m_RequireInventory;
76 protected int m_MinLoginLevel;
77 protected string m_GatekeeperURL;
78 protected bool m_AllowRemoteSetLoginLevel;
79 protected string m_MapTileURL;
80 protected string m_SearchURL;
81 protected string m_Currency;
82 protected string m_ClassifiedFee;
83 protected string m_DestinationGuide;
84 protected string m_AvatarPicker;
85  
86 protected string m_AllowedClients;
87 protected string m_DeniedClients;
88  
89 protected string m_DSTZone;
90  
91 IConfig m_LoginServerConfig;
92 // IConfig m_ClientsConfig;
93  
94 public LLLoginService(IConfigSource config, ISimulationService simService, ILibraryService libraryService)
95 {
96 m_LoginServerConfig = config.Configs["LoginService"];
97 if (m_LoginServerConfig == null)
98 throw new Exception(String.Format("No section LoginService in config file"));
99  
100 string accountService = m_LoginServerConfig.GetString("UserAccountService", String.Empty);
101 string gridUserService = m_LoginServerConfig.GetString("GridUserService", String.Empty);
102 string agentService = m_LoginServerConfig.GetString("UserAgentService", String.Empty);
103 string authService = m_LoginServerConfig.GetString("AuthenticationService", String.Empty);
104 string invService = m_LoginServerConfig.GetString("InventoryService", String.Empty);
105 string gridService = m_LoginServerConfig.GetString("GridService", String.Empty);
106 string presenceService = m_LoginServerConfig.GetString("PresenceService", String.Empty);
107 string libService = m_LoginServerConfig.GetString("LibraryService", String.Empty);
108 string friendsService = m_LoginServerConfig.GetString("FriendsService", String.Empty);
109 string avatarService = m_LoginServerConfig.GetString("AvatarService", String.Empty);
110 string simulationService = m_LoginServerConfig.GetString("SimulationService", String.Empty);
111  
112 m_DefaultRegionName = m_LoginServerConfig.GetString("DefaultRegion", String.Empty);
113 m_WelcomeMessage = m_LoginServerConfig.GetString("WelcomeMessage", "Welcome to OpenSim!");
114 m_RequireInventory = m_LoginServerConfig.GetBoolean("RequireInventory", true);
115 m_AllowRemoteSetLoginLevel = m_LoginServerConfig.GetBoolean("AllowRemoteSetLoginLevel", false);
116 m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0);
117 m_GatekeeperURL = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
118 new string[] { "Startup", "Hypergrid", "LoginService" }, String.Empty);
119 m_MapTileURL = m_LoginServerConfig.GetString("MapTileURL", string.Empty);
120 m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty);
121 m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty);
122 m_ClassifiedFee = m_LoginServerConfig.GetString("ClassifiedFee", string.Empty);
123 m_DestinationGuide = m_LoginServerConfig.GetString ("DestinationGuide", string.Empty);
124 m_AvatarPicker = m_LoginServerConfig.GetString ("AvatarPicker", string.Empty);
125  
126 m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty);
127 m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty);
128  
129 m_DSTZone = m_LoginServerConfig.GetString("DSTZone", "America/Los_Angeles;Pacific Standard Time");
130  
131 // Clean up some of these vars
132 if (m_MapTileURL != String.Empty)
133 {
134 m_MapTileURL = m_MapTileURL.Trim();
135 if (!m_MapTileURL.EndsWith("/"))
136 m_MapTileURL = m_MapTileURL + "/";
137 }
138  
139 // These are required; the others aren't
140 if (accountService == string.Empty || authService == string.Empty)
141 throw new Exception("LoginService is missing service specifications");
142  
143 // replace newlines in welcome message
144 m_WelcomeMessage = m_WelcomeMessage.Replace("\\n", "\n");
145  
146 Object[] args = new Object[] { config };
147 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
148 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
149 m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, args);
150 m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args);
151  
152 if (gridService != string.Empty)
153 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
154 if (presenceService != string.Empty)
155 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
156 if (avatarService != string.Empty)
157 m_AvatarService = ServerUtils.LoadPlugin<IAvatarService>(avatarService, args);
158 if (friendsService != string.Empty)
159 m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(friendsService, args);
160 if (simulationService != string.Empty)
161 m_RemoteSimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args);
162 if (agentService != string.Empty)
163 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(agentService, args);
164  
165 // Get the Hypergrid inventory service (exists only if Hypergrid is enabled)
166 string hgInvServicePlugin = m_LoginServerConfig.GetString("HGInventoryServicePlugin", String.Empty);
167 if (hgInvServicePlugin != string.Empty)
168 {
169 string hgInvServiceArg = m_LoginServerConfig.GetString("HGInventoryServiceConstructorArg", String.Empty);
170 Object[] args2 = new Object[] { config, hgInvServiceArg };
171 m_HGInventoryService = ServerUtils.LoadPlugin<IInventoryService>(hgInvServicePlugin, args2);
172 }
173  
174 //
175 // deal with the services given as argument
176 //
177 m_LocalSimulationService = simService;
178 if (libraryService != null)
179 {
180 m_log.DebugFormat("[LLOGIN SERVICE]: Using LibraryService given as argument");
181 m_LibraryService = libraryService;
182 }
183 else if (libService != string.Empty)
184 {
185 m_log.DebugFormat("[LLOGIN SERVICE]: Using instantiated LibraryService");
186 m_LibraryService = ServerUtils.LoadPlugin<ILibraryService>(libService, args);
187 }
188  
189 m_GatekeeperConnector = new GatekeeperServiceConnector();
190  
191 if (!Initialized)
192 {
193 Initialized = true;
194 RegisterCommands();
195 }
196  
197 m_log.DebugFormat("[LLOGIN SERVICE]: Starting...");
198  
199 }
200  
201 public LLLoginService(IConfigSource config) : this(config, null, null)
202 {
203 }
204  
205 public Hashtable SetLevel(string firstName, string lastName, string passwd, int level, IPEndPoint clientIP)
206 {
207 Hashtable response = new Hashtable();
208 response["success"] = "false";
209  
210 if (!m_AllowRemoteSetLoginLevel)
211 return response;
212  
213 try
214 {
215 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, firstName, lastName);
216 if (account == null)
217 {
218 m_log.InfoFormat("[LLOGIN SERVICE]: Set Level failed, user {0} {1} not found", firstName, lastName);
219 return response;
220 }
221  
222 if (account.UserLevel < 200)
223 {
224 m_log.InfoFormat("[LLOGIN SERVICE]: Set Level failed, reason: user level too low");
225 return response;
226 }
227  
228 //
229 // Authenticate this user
230 //
231 // We don't support clear passwords here
232 //
233 string token = m_AuthenticationService.Authenticate(account.PrincipalID, passwd, 30);
234 UUID secureSession = UUID.Zero;
235 if ((token == string.Empty) || (token != string.Empty && !UUID.TryParse(token, out secureSession)))
236 {
237 m_log.InfoFormat("[LLOGIN SERVICE]: SetLevel failed, reason: authentication failed");
238 return response;
239 }
240 }
241 catch (Exception e)
242 {
243 m_log.Error("[LLOGIN SERVICE]: SetLevel failed, exception " + e.ToString());
244 return response;
245 }
246  
247 m_MinLoginLevel = level;
248 m_log.InfoFormat("[LLOGIN SERVICE]: Login level set to {0} by {1} {2}", level, firstName, lastName);
249  
250 response["success"] = true;
251 return response;
252 }
253  
254 public LoginResponse Login(string firstName, string lastName, string passwd, string startLocation, UUID scopeID,
255 string clientVersion, string channel, string mac, string id0, IPEndPoint clientIP)
256 {
257 bool success = false;
258 UUID session = UUID.Random();
259  
260 m_log.InfoFormat("[LLOGIN SERVICE]: Login request for {0} {1} at {2} using viewer {3}, channel {4}, IP {5}, Mac {6}, Id0 {7}",
261 firstName, lastName, startLocation, clientVersion, channel, clientIP.Address.ToString(), mac, id0);
262  
263 try
264 {
265 //
266 // Check client
267 //
268 if (m_AllowedClients != string.Empty)
269 {
270 Regex arx = new Regex(m_AllowedClients);
271 Match am = arx.Match(clientVersion);
272  
273 if (!am.Success)
274 {
275 m_log.InfoFormat(
276 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: client {2} is not allowed",
277 firstName, lastName, clientVersion);
278 return LLFailedLoginResponse.LoginBlockedProblem;
279 }
280 }
281  
282 if (m_DeniedClients != string.Empty)
283 {
284 Regex drx = new Regex(m_DeniedClients);
285 Match dm = drx.Match(clientVersion);
286  
287 if (dm.Success)
288 {
289 m_log.InfoFormat(
290 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: client {2} is denied",
291 firstName, lastName, clientVersion);
292 return LLFailedLoginResponse.LoginBlockedProblem;
293 }
294 }
295  
296 //
297 // Get the account and check that it exists
298 //
299 UserAccount account = m_UserAccountService.GetUserAccount(scopeID, firstName, lastName);
300 if (account == null)
301 {
302 m_log.InfoFormat(
303 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user not found", firstName, lastName);
304 return LLFailedLoginResponse.UserProblem;
305 }
306  
307 if (account.UserLevel < m_MinLoginLevel)
308 {
309 m_log.InfoFormat(
310 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user level is {2} but minimum login level is {3}",
311 firstName, lastName, account.UserLevel, m_MinLoginLevel);
312 return LLFailedLoginResponse.LoginBlockedProblem;
313 }
314  
315 // If a scope id is requested, check that the account is in
316 // that scope, or unscoped.
317 //
318 if (scopeID != UUID.Zero)
319 {
320 if (account.ScopeID != scopeID && account.ScopeID != UUID.Zero)
321 {
322 m_log.InfoFormat(
323 "[LLOGIN SERVICE]: Login failed, reason: user {0} {1} not found", firstName, lastName);
324 return LLFailedLoginResponse.UserProblem;
325 }
326 }
327 else
328 {
329 scopeID = account.ScopeID;
330 }
331  
332 //
333 // Authenticate this user
334 //
335 if (!passwd.StartsWith("$1$"))
336 passwd = "$1$" + Util.Md5Hash(passwd);
337 passwd = passwd.Remove(0, 3); //remove $1$
338 string token = m_AuthenticationService.Authenticate(account.PrincipalID, passwd, 30);
339 UUID secureSession = UUID.Zero;
340 if ((token == string.Empty) || (token != string.Empty && !UUID.TryParse(token, out secureSession)))
341 {
342 m_log.InfoFormat(
343 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: authentication failed",
344 firstName, lastName);
345 return LLFailedLoginResponse.UserProblem;
346 }
347  
348 //
349 // Get the user's inventory
350 //
351 if (m_RequireInventory && m_InventoryService == null)
352 {
353 m_log.WarnFormat(
354 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: inventory service not set up",
355 firstName, lastName);
356 return LLFailedLoginResponse.InventoryProblem;
357 }
358  
359 if (m_HGInventoryService != null)
360 {
361 // Give the Suitcase service a chance to create the suitcase folder.
362 // (If we're not using the Suitcase inventory service then this won't do anything.)
363 m_HGInventoryService.GetRootFolder(account.PrincipalID);
364 }
365  
366 List<InventoryFolderBase> inventorySkel = m_InventoryService.GetInventorySkeleton(account.PrincipalID);
367 if (m_RequireInventory && ((inventorySkel == null) || (inventorySkel != null && inventorySkel.Count == 0)))
368 {
369 m_log.InfoFormat(
370 "[LLOGIN SERVICE]: Login failed, for {0} {1}, reason: unable to retrieve user inventory",
371 firstName, lastName);
372 return LLFailedLoginResponse.InventoryProblem;
373 }
374  
375 // Get active gestures
376 List<InventoryItemBase> gestures = m_InventoryService.GetActiveGestures(account.PrincipalID);
377 // m_log.DebugFormat("[LLOGIN SERVICE]: {0} active gestures", gestures.Count);
378  
379 //
380 // Login the presence
381 //
382 if (m_PresenceService != null)
383 {
384 success = m_PresenceService.LoginAgent(account.PrincipalID.ToString(), session, secureSession);
385  
386 if (!success)
387 {
388 m_log.InfoFormat(
389 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: could not login presence",
390 firstName, lastName);
391 return LLFailedLoginResponse.GridProblem;
392 }
393 }
394  
395 //
396 // Change Online status and get the home region
397 //
398 GridRegion home = null;
399 GridUserInfo guinfo = m_GridUserService.LoggedIn(account.PrincipalID.ToString());
400  
401 // We are only going to complain about no home if the user actually tries to login there, to avoid
402 // spamming the console.
403 if (guinfo != null)
404 {
405 if (guinfo.HomeRegionID == UUID.Zero && startLocation == "home")
406 {
407 m_log.WarnFormat(
408 "[LLOGIN SERVICE]: User {0} tried to login to a 'home' start location but they have none set",
409 account.Name);
410 }
411 else if (m_GridService != null)
412 {
413 home = m_GridService.GetRegionByUUID(scopeID, guinfo.HomeRegionID);
414  
415 if (home == null && startLocation == "home")
416 {
417 m_log.WarnFormat(
418 "[LLOGIN SERVICE]: User {0} tried to login to a 'home' start location with ID {1} but this was not found.",
419 account.Name, guinfo.HomeRegionID);
420 }
421 }
422 }
423 else
424 {
425 // something went wrong, make something up, so that we don't have to test this anywhere else
426 m_log.DebugFormat("{0} Failed to fetch GridUserInfo. Creating empty GridUserInfo as home", LogHeader);
427 guinfo = new GridUserInfo();
428 guinfo.LastPosition = guinfo.HomePosition = new Vector3(128, 128, 30);
429 }
430  
431 //
432 // Find the destination region/grid
433 //
434 string where = string.Empty;
435 Vector3 position = Vector3.Zero;
436 Vector3 lookAt = Vector3.Zero;
437 GridRegion gatekeeper = null;
438 TeleportFlags flags;
439 GridRegion destination = FindDestination(account, scopeID, guinfo, session, startLocation, home, out gatekeeper, out where, out position, out lookAt, out flags);
440 if (destination == null)
441 {
442 m_PresenceService.LogoutAgent(session);
443  
444 m_log.InfoFormat(
445 "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: destination not found",
446 firstName, lastName);
447 return LLFailedLoginResponse.GridProblem;
448 }
449 else
450 {
451 m_log.DebugFormat(
452 "[LLOGIN SERVICE]: Found destination {0}, endpoint {1} for {2} {3}",
453 destination.RegionName, destination.ExternalEndPoint, firstName, lastName);
454 }
455  
456 if (account.UserLevel >= 200)
457 flags |= TeleportFlags.Godlike;
458 //
459 // Get the avatar
460 //
461 AvatarAppearance avatar = null;
462 if (m_AvatarService != null)
463 {
464 avatar = m_AvatarService.GetAppearance(account.PrincipalID);
465 }
466  
467 //
468 // Instantiate/get the simulation interface and launch an agent at the destination
469 //
470 string reason = string.Empty;
471 GridRegion dest;
472 AgentCircuitData aCircuit = LaunchAgentAtGrid(gatekeeper, destination, account, avatar, session, secureSession, position, where,
473 clientVersion, channel, mac, id0, clientIP, flags, out where, out reason, out dest);
474 destination = dest;
475 if (aCircuit == null)
476 {
477 m_PresenceService.LogoutAgent(session);
478 m_log.InfoFormat("[LLOGIN SERVICE]: Login failed for {0} {1}, reason: {2}", firstName, lastName, reason);
479 return new LLFailedLoginResponse("key", reason, "false");
480  
481 }
482 // Get Friends list
483 FriendInfo[] friendsList = new FriendInfo[0];
484 if (m_FriendsService != null)
485 {
486 friendsList = m_FriendsService.GetFriends(account.PrincipalID);
487 // m_log.DebugFormat("[LLOGIN SERVICE]: Retrieved {0} friends", friendsList.Length);
488 }
489  
490 //
491 // Finally, fill out the response and return it
492 //
493 LLLoginResponse response
494 = new LLLoginResponse(
495 account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService,
496 where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP,
497 m_MapTileURL, m_SearchURL, m_Currency, m_DSTZone,
498 m_DestinationGuide, m_AvatarPicker, m_ClassifiedFee);
499  
500 m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName);
501  
502 return response;
503 }
504 catch (Exception e)
505 {
506 m_log.WarnFormat("[LLOGIN SERVICE]: Exception processing login for {0} {1}: {2} {3}", firstName, lastName, e.ToString(), e.StackTrace);
507 if (m_PresenceService != null)
508 m_PresenceService.LogoutAgent(session);
509 return LLFailedLoginResponse.InternalError;
510 }
511 }
512  
513 protected GridRegion FindDestination(
514 UserAccount account, UUID scopeID, GridUserInfo pinfo, UUID sessionID, string startLocation,
515 GridRegion home, out GridRegion gatekeeper,
516 out string where, out Vector3 position, out Vector3 lookAt, out TeleportFlags flags)
517 {
518 flags = TeleportFlags.ViaLogin;
519  
520 m_log.DebugFormat(
521 "[LLOGIN SERVICE]: Finding destination matching start location {0} for {1}",
522 startLocation, account.Name);
523  
524 gatekeeper = null;
525 where = "home";
526 position = new Vector3(128, 128, 0);
527 lookAt = new Vector3(0, 1, 0);
528  
529 if (m_GridService == null)
530 return null;
531  
532 if (startLocation.Equals("home"))
533 {
534 // logging into home region
535 if (pinfo == null)
536 return null;
537  
538 GridRegion region = null;
539  
540 bool tryDefaults = false;
541  
542 if (home == null)
543 {
544 tryDefaults = true;
545 }
546 else
547 {
548 region = home;
549  
550 position = pinfo.HomePosition;
551 lookAt = pinfo.HomeLookAt;
552 flags |= TeleportFlags.ViaHome;
553 }
554  
555 if (tryDefaults)
556 {
557 List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID);
558 if (defaults != null && defaults.Count > 0)
559 {
560 region = defaults[0];
561 where = "safe";
562 }
563 else
564 {
565 m_log.WarnFormat("[LLOGIN SERVICE]: User {0} {1} does not have a valid home and this grid does not have default locations. Attempting to find random region",
566 account.FirstName, account.LastName);
567 region = FindAlternativeRegion(scopeID);
568 if (region != null)
569 where = "safe";
570 }
571 }
572  
573 return region;
574 }
575 else if (startLocation.Equals("last"))
576 {
577 // logging into last visited region
578 where = "last";
579  
580 if (pinfo == null)
581 return null;
582  
583 GridRegion region = null;
584  
585 if (pinfo.LastRegionID.Equals(UUID.Zero) || (region = m_GridService.GetRegionByUUID(scopeID, pinfo.LastRegionID)) == null)
586 {
587 List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID);
588 if (defaults != null && defaults.Count > 0)
589 {
590 region = defaults[0];
591 where = "safe";
592 }
593 else
594 {
595 m_log.Info("[LLOGIN SERVICE]: Last Region Not Found Attempting to find random region");
596 region = FindAlternativeRegion(scopeID);
597 if (region != null)
598 where = "safe";
599 }
600  
601 }
602 else
603 {
604 position = pinfo.LastPosition;
605 lookAt = pinfo.LastLookAt;
606 }
607  
608 return region;
609 }
610 else
611 {
612 flags |= TeleportFlags.ViaRegionID;
613  
614 // free uri form
615 // e.g. New Moon&135&46 New Moon@osgrid.org:8002&153&34
616 where = "url";
617 GridRegion region = null;
618 Regex reURI = new Regex(@"^uri:(?<region>[^&]+)&(?<x>\d+)&(?<y>\d+)&(?<z>\d+)$");
619 Match uriMatch = reURI.Match(startLocation);
620 if (uriMatch == null)
621 {
622 m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, but can't process it", startLocation);
623 return null;
624 }
625 else
626 {
627 position = new Vector3(float.Parse(uriMatch.Groups["x"].Value, Culture.NumberFormatInfo),
628 float.Parse(uriMatch.Groups["y"].Value, Culture.NumberFormatInfo),
629 float.Parse(uriMatch.Groups["z"].Value, Culture.NumberFormatInfo));
630  
631 string regionName = uriMatch.Groups["region"].ToString();
632 if (regionName != null)
633 {
634 if (!regionName.Contains("@"))
635 {
636 List<GridRegion> regions = m_GridService.GetRegionsByName(scopeID, regionName, 1);
637 if ((regions == null) || (regions != null && regions.Count == 0))
638 {
639 m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, can't locate region {1}. Trying defaults.", startLocation, regionName);
640 regions = m_GridService.GetDefaultRegions(scopeID);
641 if (regions != null && regions.Count > 0)
642 {
643 where = "safe";
644 return regions[0];
645 }
646 else
647 {
648 m_log.Info("[LLOGIN SERVICE]: Last Region Not Found Attempting to find random region");
649 region = FindAlternativeRegion(scopeID);
650 if (region != null)
651 {
652 where = "safe";
653 return region;
654 }
655 else
656 {
657 m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, Grid does not provide default regions and no alternative found.", startLocation);
658 return null;
659 }
660 }
661 }
662 return regions[0];
663 }
664 else
665 {
666 if (m_UserAgentService == null)
667 {
668 m_log.WarnFormat("[LLLOGIN SERVICE]: This llogin service is not running a user agent service, as such it can't lauch agents at foreign grids");
669 return null;
670 }
671 string[] parts = regionName.Split(new char[] { '@' });
672 if (parts.Length < 2)
673 {
674 m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, can't locate region {1}", startLocation, regionName);
675 return null;
676 }
677 // Valid specification of a remote grid
678  
679 regionName = parts[0];
680 string domainLocator = parts[1];
681 parts = domainLocator.Split(new char[] {':'});
682 string domainName = parts[0];
683 uint port = 0;
684 if (parts.Length > 1)
685 UInt32.TryParse(parts[1], out port);
686  
687 region = FindForeignRegion(domainName, port, regionName, account, out gatekeeper);
688 return region;
689 }
690 }
691 else
692 {
693 List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID);
694 if (defaults != null && defaults.Count > 0)
695 {
696 where = "safe";
697 return defaults[0];
698 }
699 else
700 return null;
701 }
702 }
703 //response.LookAt = "[r0,r1,r0]";
704 //// can be: last, home, safe, url
705 //response.StartLocation = "url";
706  
707 }
708  
709 }
710  
711 private GridRegion FindAlternativeRegion(UUID scopeID)
712 {
713 List<GridRegion> hyperlinks = null;
714 List<GridRegion> regions = m_GridService.GetFallbackRegions(scopeID, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000));
715 if (regions != null && regions.Count > 0)
716 {
717 hyperlinks = m_GridService.GetHyperlinks(scopeID);
718 IEnumerable<GridRegion> availableRegions = regions.Except(hyperlinks);
719 if (availableRegions.Count() > 0)
720 return availableRegions.ElementAt(0);
721 }
722 // No fallbacks, try to find an arbitrary region that is not a hyperlink
723 // maxNumber is fixed for now; maybe use some search pattern with increasing maxSize here?
724 regions = m_GridService.GetRegionsByName(scopeID, "", 10);
725 if (regions != null && regions.Count > 0)
726 {
727 if (hyperlinks == null)
728 hyperlinks = m_GridService.GetHyperlinks(scopeID);
729 IEnumerable<GridRegion> availableRegions = regions.Except(hyperlinks);
730 if (availableRegions.Count() > 0)
731 return availableRegions.ElementAt(0);
732 }
733 return null;
734 }
735  
736 private GridRegion FindForeignRegion(string domainName, uint port, string regionName, UserAccount account, out GridRegion gatekeeper)
737 {
738 m_log.Debug("[LLLOGIN SERVICE]: attempting to findforeignregion " + domainName + ":" + port.ToString() + ":" + regionName);
739 gatekeeper = new GridRegion();
740 gatekeeper.ExternalHostName = domainName;
741 gatekeeper.HttpPort = port;
742 gatekeeper.RegionName = regionName;
743 gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
744  
745 UUID regionID;
746 ulong handle;
747 string imageURL = string.Empty, reason = string.Empty;
748 string message;
749 if (m_GatekeeperConnector.LinkRegion(gatekeeper, out regionID, out handle, out domainName, out imageURL, out reason))
750 {
751 string homeURI = null;
752 if (account.ServiceURLs != null && account.ServiceURLs.ContainsKey("HomeURI"))
753 homeURI = (string)account.ServiceURLs["HomeURI"];
754  
755 GridRegion destination = m_GatekeeperConnector.GetHyperlinkRegion(gatekeeper, regionID, account.PrincipalID, homeURI, out message);
756 return destination;
757 }
758  
759 return null;
760 }
761  
762 private string hostName = string.Empty;
763 private int port = 0;
764  
765 private void SetHostAndPort(string url)
766 {
767 try
768 {
769 Uri uri = new Uri(url);
770 hostName = uri.Host;
771 port = uri.Port;
772 }
773 catch
774 {
775 m_log.WarnFormat("[LLLogin SERVICE]: Unable to parse GatekeeperURL {0}", url);
776 }
777 }
778  
779 protected AgentCircuitData LaunchAgentAtGrid(GridRegion gatekeeper, GridRegion destination, UserAccount account, AvatarAppearance avatar,
780 UUID session, UUID secureSession, Vector3 position, string currentWhere, string viewer, string channel, string mac, string id0,
781 IPEndPoint clientIP, TeleportFlags flags, out string where, out string reason, out GridRegion dest)
782 {
783 where = currentWhere;
784 ISimulationService simConnector = null;
785 reason = string.Empty;
786 uint circuitCode = 0;
787 AgentCircuitData aCircuit = null;
788  
789 if (m_UserAgentService == null)
790 {
791 // HG standalones have both a localSimulatonDll and a remoteSimulationDll
792 // non-HG standalones have just a localSimulationDll
793 // independent login servers have just a remoteSimulationDll
794 if (m_LocalSimulationService != null)
795 simConnector = m_LocalSimulationService;
796 else if (m_RemoteSimulationService != null)
797 simConnector = m_RemoteSimulationService;
798 }
799 else // User Agent Service is on
800 {
801 if (gatekeeper == null) // login to local grid
802 {
803 if (hostName == string.Empty)
804 SetHostAndPort(m_GatekeeperURL);
805  
806 gatekeeper = new GridRegion(destination);
807 gatekeeper.ExternalHostName = hostName;
808 gatekeeper.HttpPort = (uint)port;
809 gatekeeper.ServerURI = m_GatekeeperURL;
810 }
811 m_log.Debug("[LLLOGIN SERVICE]: no gatekeeper detected..... using " + m_GatekeeperURL);
812 }
813  
814 bool success = false;
815  
816 if (m_UserAgentService == null && simConnector != null)
817 {
818 circuitCode = (uint)Util.RandomClass.Next(); ;
819 aCircuit = MakeAgent(destination, account, avatar, session, secureSession, circuitCode, position, clientIP.Address.ToString(), viewer, channel, mac, id0);
820 success = LaunchAgentDirectly(simConnector, destination, aCircuit, flags, out reason);
821 if (!success && m_GridService != null)
822 {
823 // Try the fallback regions
824 List<GridRegion> fallbacks = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY);
825 if (fallbacks != null)
826 {
827 foreach (GridRegion r in fallbacks)
828 {
829 success = LaunchAgentDirectly(simConnector, r, aCircuit, flags | TeleportFlags.ViaRegionID, out reason);
830 if (success)
831 {
832 where = "safe";
833 destination = r;
834 break;
835 }
836 }
837 }
838 }
839 }
840  
841 if (m_UserAgentService != null)
842 {
843 circuitCode = (uint)Util.RandomClass.Next(); ;
844 aCircuit = MakeAgent(destination, account, avatar, session, secureSession, circuitCode, position, clientIP.Address.ToString(), viewer, channel, mac, id0);
845 aCircuit.teleportFlags |= (uint)flags;
846 success = LaunchAgentIndirectly(gatekeeper, destination, aCircuit, clientIP, out reason);
847 if (!success && m_GridService != null)
848 {
849 // Try the fallback regions
850 List<GridRegion> fallbacks = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY);
851 if (fallbacks != null)
852 {
853 foreach (GridRegion r in fallbacks)
854 {
855 success = LaunchAgentIndirectly(gatekeeper, r, aCircuit, clientIP, out reason);
856 if (success)
857 {
858 where = "safe";
859 destination = r;
860 break;
861 }
862 }
863 }
864 }
865 }
866 dest = destination;
867 if (success)
868 return aCircuit;
869 else
870 return null;
871 }
872  
873 private AgentCircuitData MakeAgent(GridRegion region, UserAccount account,
874 AvatarAppearance avatar, UUID session, UUID secureSession, uint circuit, Vector3 position,
875 string ipaddress, string viewer, string channel, string mac, string id0)
876 {
877 AgentCircuitData aCircuit = new AgentCircuitData();
878  
879 aCircuit.AgentID = account.PrincipalID;
880 if (avatar != null)
881 aCircuit.Appearance = new AvatarAppearance(avatar);
882 else
883 aCircuit.Appearance = new AvatarAppearance();
884  
885 //aCircuit.BaseFolder = irrelevant
886 aCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
887 aCircuit.child = false; // the first login agent is root
888 aCircuit.ChildrenCapSeeds = new Dictionary<ulong, string>();
889 aCircuit.circuitcode = circuit;
890 aCircuit.firstname = account.FirstName;
891 //aCircuit.InventoryFolder = irrelevant
892 aCircuit.lastname = account.LastName;
893 aCircuit.SecureSessionID = secureSession;
894 aCircuit.SessionID = session;
895 aCircuit.startpos = position;
896 aCircuit.IPAddress = ipaddress;
897 aCircuit.Viewer = viewer;
898 aCircuit.Channel = channel;
899 aCircuit.Mac = mac;
900 aCircuit.Id0 = id0;
901 SetServiceURLs(aCircuit, account);
902  
903 return aCircuit;
904 }
905  
906 private void SetServiceURLs(AgentCircuitData aCircuit, UserAccount account)
907 {
908 aCircuit.ServiceURLs = new Dictionary<string, object>();
909 if (account.ServiceURLs == null)
910 return;
911  
912 // Old style: get the service keys from the DB
913 foreach (KeyValuePair<string, object> kvp in account.ServiceURLs)
914 {
915 if (kvp.Value != null)
916 {
917 aCircuit.ServiceURLs[kvp.Key] = kvp.Value;
918  
919 if (!aCircuit.ServiceURLs[kvp.Key].ToString().EndsWith("/"))
920 aCircuit.ServiceURLs[kvp.Key] = aCircuit.ServiceURLs[kvp.Key] + "/";
921 }
922 }
923  
924 // New style: service keys start with SRV_; override the previous
925 string[] keys = m_LoginServerConfig.GetKeys();
926  
927 if (keys.Length > 0)
928 {
929 bool newUrls = false;
930 IEnumerable<string> serviceKeys = keys.Where(value => value.StartsWith("SRV_"));
931 foreach (string serviceKey in serviceKeys)
932 {
933 string keyName = serviceKey.Replace("SRV_", "");
934 string keyValue = m_LoginServerConfig.GetString(serviceKey, string.Empty);
935 if (!keyValue.EndsWith("/"))
936 keyValue = keyValue + "/";
937  
938 if (!account.ServiceURLs.ContainsKey(keyName) || (account.ServiceURLs.ContainsKey(keyName) && (string)account.ServiceURLs[keyName] != keyValue))
939 {
940 account.ServiceURLs[keyName] = keyValue;
941 newUrls = true;
942 }
943 aCircuit.ServiceURLs[keyName] = keyValue;
944  
945 m_log.DebugFormat("[LLLOGIN SERVICE]: found new key {0} {1}", keyName, aCircuit.ServiceURLs[keyName]);
946 }
947  
948 // The grid operator decided to override the defaults in the
949 // [LoginService] configuration. Let's store the correct ones.
950 if (newUrls)
951 m_UserAccountService.StoreUserAccount(account);
952 }
953  
954 }
955  
956 private bool LaunchAgentDirectly(ISimulationService simConnector, GridRegion region, AgentCircuitData aCircuit, TeleportFlags flags, out string reason)
957 {
958 string version;
959  
960 if (
961 !simConnector.QueryAccess(
962 region, aCircuit.AgentID, null, true, aCircuit.startpos, "SIMULATION/0.3", out version, out reason))
963 return false;
964  
965 return simConnector.CreateAgent(null, region, aCircuit, (uint)flags, out reason);
966 }
967  
968 private bool LaunchAgentIndirectly(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, IPEndPoint clientIP, out string reason)
969 {
970 m_log.Debug("[LLOGIN SERVICE]: Launching agent at " + destination.RegionName);
971  
972 if (m_UserAgentService.LoginAgentToGrid(null, aCircuit, gatekeeper, destination, true, out reason))
973 return true;
974 return false;
975 }
976  
977 #region Console Commands
978 private void RegisterCommands()
979 {
980 //MainConsole.Instance.Commands.AddCommand
981 MainConsole.Instance.Commands.AddCommand("Users", false, "login level",
982 "login level <level>",
983 "Set the minimum user level to log in", HandleLoginCommand);
984  
985 MainConsole.Instance.Commands.AddCommand("Users", false, "login reset",
986 "login reset",
987 "Reset the login level to allow all users",
988 HandleLoginCommand);
989  
990 MainConsole.Instance.Commands.AddCommand("Users", false, "login text",
991 "login text <text>",
992 "Set the text users will see on login", HandleLoginCommand);
993  
994 }
995  
996 private void HandleLoginCommand(string module, string[] cmd)
997 {
998 string subcommand = cmd[1];
999  
1000 switch (subcommand)
1001 {
1002 case "level":
1003 // Set the minimum level to allow login
1004 // Useful to allow grid update without worrying about users.
1005 // or fixing critical issues
1006 //
1007 if (cmd.Length > 2)
1008 {
1009 if (Int32.TryParse(cmd[2], out m_MinLoginLevel))
1010 MainConsole.Instance.OutputFormat("Set minimum login level to {0}", m_MinLoginLevel);
1011 else
1012 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid login level", cmd[2]);
1013 }
1014 break;
1015  
1016 case "reset":
1017 m_MinLoginLevel = 0;
1018 MainConsole.Instance.OutputFormat("Reset min login level to {0}", m_MinLoginLevel);
1019 break;
1020  
1021 case "text":
1022 if (cmd.Length > 2)
1023 {
1024 m_WelcomeMessage = cmd[2];
1025 MainConsole.Instance.OutputFormat("Login welcome message set to '{0}'", m_WelcomeMessage);
1026 }
1027 break;
1028 }
1029 }
1030 }
1031  
1032 #endregion
1033 }