// FIXME: these all should probably go into the respective region // modules // multiple fetch-folder maps are allowed within the larger folders map. public string FetchInventoryRequest(string request, string path, string param) { m_log.Debug("[Caps]: Inventory Request in region: " + m_regionName); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException pe) { m_log.Error("[Agent Inventory]: Fetch error: " + pe.Message); m_log.Error("Request: " + request.ToString()); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } if (response.Length == 0) { // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. // Therefore, I'm concluding that the client only has so many threads available to do requests // and when a thread stalls.. is stays stalled. // Therefore we need to return something valid response = "<llsd><map><key>folders</key><array /></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } return(response); }
/// <summary> /// Construct an LLSD reply packet to a CAPS inventory request /// </summary> /// <param name="invFetch"></param> /// <returns></returns> private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) { LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); contents.agent_id = m_agentID; contents.owner_id = invFetch.owner_id; contents.folder_id = invFetch.folder_id; reply.folders.Array.Add(contents); InventoryCollection inv = new InventoryCollection(); inv.Folders = new List <InventoryFolderBase>(); inv.Items = new List <InventoryItemBase>(); int version = 0; if (CAPSFetchInventoryDescendents != null) { inv = CAPSFetchInventoryDescendents(m_agentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version); } if (inv.Folders != null) { foreach (InventoryFolderBase invFolder in inv.Folders) { contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); } } if (inv.Items != null) { foreach (InventoryItemBase invItem in inv.Items) { contents.items.Array.Add(ConvertInventoryItem(invItem)); } } contents.descendents = contents.items.Array.Count + contents.categories.Array.Count; contents.version = version; return(reply); }
/// <summary> /// Construct an LLSD reply packet to a CAPS inventory request /// </summary> /// <param name="invFetch"></param> /// <returns></returns> private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) { LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); contents.agent_id = m_agentID; contents.owner_id = invFetch.owner_id; contents.folder_id = invFetch.folder_id; reply.folders.Array.Add(contents); InventoryCollection inv = new InventoryCollection(); inv.Folders = new List<InventoryFolderBase>(); inv.Items = new List<InventoryItemBase>(); int version = 0; if (CAPSFetchInventoryDescendents != null) { inv = CAPSFetchInventoryDescendents(m_agentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version); } if (inv.Folders != null) { foreach (InventoryFolderBase invFolder in inv.Folders) { contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); } } if (inv.Items != null) { foreach (InventoryItemBase invItem in inv.Items) { contents.items.Array.Add(ConvertInventoryItem(invItem)); } } contents.descendents = contents.items.Array.Count + contents.categories.Array.Count; contents.version = version; return reply; }
public string FetchInventoryDescendentsRequest(string request, string path, string param,OSHttpRequest httpRequest, OSHttpResponse httpResponse) { // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid // request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException pe) { m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); m_log.Error("Request: " + request.ToString()); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; lock (m_fetchLock) { for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try{ LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch(Exception e) { m_log.Debug("[CAPS]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } if (response.Length == 0) { // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. // Therefore, I'm concluding that the client only has so many threads available to do requests // and when a thread stalls.. is stays stalled. // Therefore we need to return something valid response = "<llsd><map><key>folders</key><array /></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } //m_log.DebugFormat("[CAPS]: Replying to CAPS fetch inventory request with following xml"); //m_log.Debug("[CAPS] "+response); } return response; }
// FIXME: these all should probably go into the respective region // modules /// <summary> /// Processes a fetch inventory request and sends the reply /// </summary> /// <param name="request"></param> /// <param name="path"></param> /// <param name="param"></param> /// <returns></returns> // Request is like: //<llsd> // <map><key>folders</key> // <array> // <map> // <key>fetch-folders</key><boolean>1</boolean><key>fetch-items</key><boolean>1</boolean><key>folder-id</key><uuid>8e1e3a30-b9bf-11dc-95ff-0800200c9a66</uuid><key>owner-id</key><uuid>11111111-1111-0000-0000-000100bba000</uuid><key>sort-order</key><integer>1</integer> // </map> // </array> // </map> //</llsd> // // multiple fetch-folder maps are allowed within the larger folders map. public string FetchInventoryRequest(string request, string path, string param) { // string unmodifiedRequest = request.ToString(); //m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request {0}", unmodifiedRequest); m_log.Debug("[CAPS]: Inventory Request in region: " + m_regionName); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException pe) { m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); m_log.Error("Request: " + request.ToString()); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } if (response.Length == 0) { // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. // Therefore, I'm concluding that the client only has so many threads available to do requests // and when a thread stalls.. is stays stalled. // Therefore we need to return something valid response = "<llsd><map><key>folders</key><array /></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml"); //m_log.Debug(Util.GetFormattedXml(response)); return response; }
/// <summary> /// Processes a fetch inventory request and sends the reply /// </summary> /// <param name="request"></param> /// <param name="path"></param> /// <param name="param"></param> /// <returns></returns> // Request is like: //<llsd> // <map><key>folders</key> // <array> // <map> // <key>fetch-folders</key><boolean>1</boolean><key>fetch-items</key><boolean>1</boolean><key>folder-id</key><uuid>8e1e3a30-b9bf-11dc-95ff-0800200c9a66</uuid><key>owner-id</key><uuid>11111111-1111-0000-0000-000100bba000</uuid><key>sort-order</key><integer>1</integer> // </map> // </array> // </map> //</llsd> // // multiple fetch-folder maps are allowed within the larger folders map. public Hashtable FetchInventoryRequest(Hashtable mDhttpMethod, UUID agentID) { m_log.DebugFormat("[AGENT INVENTORY]: Received CAPS fetch inventory request for {0}", agentID); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(OpenMetaverse.Utils.StringToBytes((string)mDhttpMethod["requestbody"])); } catch (LLSD.LLSDParseException pe) { m_log.Error("[AGENT INVENTORY]: Fetch error: " + pe.Message); //m_log.Error("Request: " + request.ToString()); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest, agentID, false); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } if (response.Length == 0) { // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. // Therefore, I'm concluding that the client only has so many threads available to do requests // and when a thread stalls.. is stays stalled. // Therefore we need to return something valid response = "<llsd><map><key>folders</key><array /></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } //m_log.DebugFormat("[AGENT INVENTORY]: Replying to CAPS fetch inventory request with following xml"); //m_log.Debug(Util.GetFormattedXml(response)); Hashtable cancelresponsedata = new Hashtable(); cancelresponsedata["int_response_code"] = 200; //501; //410; //404; cancelresponsedata["content_type"] = "text/plain"; cancelresponsedata["keepalive"] = false; cancelresponsedata["str_response_string"] = response; return cancelresponsedata; }
private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll) { InventoryCollection contents = coll.Collection; if (freq.fetch_items && contents.Items != null) { List<InventoryItemBase> itemsToReturn = contents.Items; // descendents must only include the links, not the linked items we add coll.Descendents = itemsToReturn.Count; // Add target items for links in this folder before the links themselves. List<UUID> itemIDs = new List<UUID>(); List<UUID> folderIDs = new List<UUID>(); foreach (InventoryItemBase item in itemsToReturn) { //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); if (item.AssetType == (int)AssetType.Link) itemIDs.Add(item.AssetID); // else if (item.AssetType == (int)AssetType.LinkFolder) // folderIDs.Add(item.AssetID); } //m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count); // Scan for folder links and insert the items they target and those links at the head of the return data if (folderIDs.Count > 0) { InventoryCollection[] linkedFolders = m_InventoryService.GetMultipleFoldersContent(coll.Collection.OwnerID, folderIDs.ToArray()); foreach (InventoryCollection linkedFolderContents in linkedFolders) { if (linkedFolderContents == null) continue; List<InventoryItemBase> links = linkedFolderContents.Items; itemsToReturn.InsertRange(0, links); } } if (itemIDs.Count > 0) { InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); if (linked == null) { // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); linked = new InventoryItemBase[itemIDs.Count]; int i = 0; InventoryItemBase item = new InventoryItemBase(); item.Owner = freq.owner_id; foreach (UUID id in itemIDs) { item.ID = id; linked[i++] = m_InventoryService.GetItem(item); } } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Processing folder {0}. Existing items:", freq.folder_id); //foreach (InventoryItemBase item in itemsToReturn) // m_log.DebugFormat("[XXX]: {0} {1} {2}", item.Name, item.AssetType, item.Folder); if (linked != null) { foreach (InventoryItemBase linkedItem in linked) { // Take care of genuinely broken links where the target doesn't exist // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles // rather than having to keep track of every folder requested in the recursion. if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) { itemsToReturn.Insert(0, linkedItem); //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); } } } } } }
private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List<UUID> bad_folders) { bool bad = false; if (contents == null) { bad_folders.Add(freq.folder_id); bad = true; } // The inventory server isn't sending FolderID in the collection... // Must fetch it individually else if (contents.FolderID == UUID.Zero) { InventoryFolderBase containingFolder = new InventoryFolderBase(); containingFolder.ID = freq.folder_id; containingFolder.Owner = freq.owner_id; containingFolder = m_InventoryService.GetFolder(containingFolder); if (containingFolder != null) { contents.FolderID = containingFolder.ID; contents.OwnerID = containingFolder.Owner; contents.Version = containingFolder.Version; } else { // Was it really a request for folder Zero? // This is an overkill, but Firestorm really asks for folder Zero. // I'm leaving the code here for the time being, but commented. if (freq.folder_id == UUID.Zero) { //coll.Collection.OwnerID = freq.owner_id; //coll.Collection.FolderID = contents.FolderID; //containingFolder = m_InventoryService.GetRootFolder(freq.owner_id); //if (containingFolder != null) //{ // m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Request for parent of folder {0}", containingFolder.ID); // coll.Collection.Folders.Clear(); // coll.Collection.Folders.Add(containingFolder); // if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null) // { // InventoryFolderBase lib = new InventoryFolderBase(m_LibraryService.LibraryRootFolder.ID, m_LibraryService.LibraryRootFolder.Owner); // lib.Name = m_LibraryService.LibraryRootFolder.Name; // lib.Type = m_LibraryService.LibraryRootFolder.Type; // lib.Version = m_LibraryService.LibraryRootFolder.Version; // coll.Collection.Folders.Add(lib); // } // coll.Collection.Items.Clear(); //} } else { m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id); bad_folders.Add(freq.folder_id); } bad = true; } } return bad; }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid // request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException e) { m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; string bad_folders_response = ""; List<LLSDFetchInventoryDescendents> folders = new List<LLSDFetchInventoryDescendents>(); for (int i = 0; i < foldersrequested.Count; i++) { Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); continue; } // Filter duplicate folder ids that bad viewers may send if (folders.Find(f => f.folder_id == llsdRequest.folder_id) == null) folders.Add(llsdRequest); } if (folders.Count > 0) { List<UUID> bad_folders = new List<UUID>(); List<InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders); //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); if (invcollSet == null) { m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol."); #pragma warning disable 0612 return FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse); #pragma warning restore 0612 } string inventoryitemstr = string.Empty; foreach (InventoryCollectionWithDescendents icoll in invcollSet) { LLSDInventoryDescendents reply = ToLLSD(icoll.Collection, icoll.Descendents); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); foreach (UUID bad in bad_folders) bad_folders_response += "<uuid>" + bad + "</uuid>"; } if (response.Length == 0) { /* Viewers expect a bad_folders array when not available */ if (bad_folders_response.Length != 0) { response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array /></map></llsd>"; } } else { if (bad_folders_response.Length != 0) { response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request for {0} folders. Item count {1}", folders.Count, item_count); //m_log.Debug("[WEB FETCH INV DESC HANDLER] " + response); return response; }
private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count); string response = ""; string bad_folders_response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); if (null == reply) { bad_folders_response += "<uuid>" + llsdRequest.folder_id.ToString() + "</uuid>"; } else { inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); } response += inventoryitemstr; } if (response.Length == 0) { /* Viewers expect a bad_folders array when not available */ if (bad_folders_response.Length != 0) { response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array /></map></llsd>"; } } else { if (bad_folders_response.Length != 0) { response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } } // m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response); return response; // } }
/// <summary> /// Construct an LLSD reply packet to a CAPS inventory request /// </summary> /// <param name="invFetch"></param> /// <returns></returns> private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) { LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); contents.agent_id = invFetch.owner_id; contents.owner_id = invFetch.owner_id; contents.folder_id = invFetch.folder_id; reply.folders.Array.Add(contents); InventoryCollection inv = new InventoryCollection(); inv.Folders = new List<InventoryFolderBase>(); inv.Items = new List<InventoryItemBase>(); int version = 0; int descendents = 0; #pragma warning disable 0612 inv = Fetch( invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents); #pragma warning restore 0612 if (inv != null && inv.Folders != null) { foreach (InventoryFolderBase invFolder in inv.Folders) { contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); } descendents += inv.Folders.Count; } if (inv != null && inv.Items != null) { foreach (InventoryItemBase invItem in inv.Items) { contents.items.Array.Add(ConvertInventoryItem(invItem)); } } contents.descendents = descendents; contents.version = version; //m_log.DebugFormat( // "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}", // invFetch.folder_id, // invFetch.fetch_items, // invFetch.fetch_folders, // contents.items.Array.Count, // contents.categories.Array.Count, // invFetch.owner_id); return reply; }
public string FetchInventoryDescendentsRequest(string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException pe) { m_log.Error("[Agent Inventory]: Fetch error: " + pe.Message); m_log.Error("Request: " + request.ToString()); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; lock (m_fetchLock) { for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[Caps]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } if (response.Length == 0) { // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. // Therefore, I'm concluding that the client only has so many threads available to do requests // and when a thread stalls.. is stays stalled. // Therefore we need to return something valid response = "<llsd><map><key>folders</key><array /></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } } return(response); }
/// <summary> /// Construct an LLSD reply packet to a CAPS inventory request /// </summary> /// <param name="invFetch"></param> /// <returns></returns> private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) { LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); contents.agent_id = m_agentID; contents.owner_id = invFetch.owner_id; contents.folder_id = invFetch.folder_id; // The version number being sent back was originally 1. // Unfortunately, on 1.19.1.4, this means that we see a problem where on subsequent logins // without clearing client cache, objects in the root folder disappear until the cache is cleared, // at which point they reappear. // // Seeing the version to something other than 0 may be the right thing to do, but there is // a greater subtlety of the second life protocol that needs to be understood first. contents.version = 0; contents.descendents = 0; reply.folders.Array.Add(contents); List<InventoryItemBase> itemList = null; if (CAPSFetchInventoryDescendents != null) { itemList = CAPSFetchInventoryDescendents(m_agentID, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order); } if (itemList != null) { foreach (InventoryItemBase invItem in itemList) { contents.items.Array.Add(ConvertInventoryItem(invItem)); } } /* The following block is removed as it ALWAYS sends the error to the client because the RC 1.22.9 client tries to find items that have become dissasociated with a paret folder and have parent of 00000000-0000-00000.... else { IClientAPI client = GetClient(m_agentID); // We're going to both notify the client of inventory service failure and send back a 'no folder contents' response. // If we don't send back the response, // the client becomes unhappy (see Teravus' comment in FetchInventoryRequest()) if (client != null) { client.SendAgentAlertMessage( "AGIN0001E: The inventory service has either failed or is not responding. Your inventory will not function properly for the rest of this session. Please clear your cache and relog.", true); } else { m_log.ErrorFormat( "[AGENT INVENTORY]: Could not lookup controlling client for {0} in order to notify them of the inventory service failure", m_agentID); } }*/ contents.descendents = contents.items.Array.Count; return reply; }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid // request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException e) { m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); throw; } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; string bad_folders_response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); if (null == reply) { bad_folders_response += "<uuid>" + llsdRequest.folder_id.ToString() + "</uuid>"; } else { inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } } if (response.Length == 0) { /* Viewers expect a bad_folders array when not available */ if (bad_folders_response.Length != 0) { response = "<llsd><map><key>bad_folders</key><array>"+bad_folders_response+"</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array /></map></llsd>"; } } else { if (bad_folders_response.Length != 0) { response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } } return response; }