clockwerk-opensim-stable – Blame information for rev 3

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