opensim-development – Blame information for rev 1

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