/// <summary> /// Handles the remaining Image data that did not fit in the initial ImageData packet /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> public void ImagePacketCallbackHandler(Packet packet, Simulator simulator) { #if DEBUG_PACKETS slClient.DebugLog(packet); #endif ImagePacketPacket reply = (ImagePacketPacket)packet; LLUUID ImageID = reply.ImageID.ID; // Lookup the request for this packet TransferRequest tr = null; lock (htDownloadRequests) { if (htDownloadRequests.ContainsKey(ImageID)) { tr = (TransferRequest)htDownloadRequests[ImageID]; } else { // Received a packet that doesn't belong to any requests in our queue, strange... return; } } // TODO: Received data should probably be put into a temporary collection that's indected by ImageID.Packet // then once we've received all data packets, it should be re-assembled into a complete array and marked // completed. // FIXME: Sometimes this gets called before ImageDataCallbackHandler, when that // happens tr.AssetData will be null. Implimenting the above TODO should fix this. // Wait until we've received the header packet for this image, which creates the AssetData array if (!tr.ReceivedHeaderPacket.WaitOne(15000, false)) { tr.Status = false; tr.StatusMsg = "Failed to receive Image Header packet in a timely manor, aborting."; slClient.Log(tr.StatusMsg, Helpers.LogLevel.Error); tr.Completed.Set(); } // Add this packet's data to the request. Buffer.BlockCopy(reply.ImageData.Data, 0, tr.AssetData, tr.BaseDataReceived + (1000 * (reply.ImageID.Packet - 1)), reply.ImageData.Data.Length); tr.Received += (uint)reply.ImageData.Data.Length; tr.TimeOfLastPacket = Helpers.GetUnixTime(); // last time we recevied a packet for this request // If we've gotten all the data, mark it completed. if (tr.Received >= tr.Size) { tr.Status = true; tr.Completed.Set(); // Fire off image downloaded event CacheImage(ImageID, tr.AssetData); FireImageRetrieved(ImageID, tr.AssetData, false); } }
public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) { ImagePacketPacket im = new ImagePacketPacket(); im.Header.Reliable = false; im.ImageID.Packet = partNumber; im.ImageID.ID = imageUuid; im.ImageData.Data = imageData; sentpktpkt.Add(im); }
private void SendImageNextPart(ushort packetNumber, byte[] imageData) { ImagePacketPacket packet = new ImagePacketPacket(); packet.ImageID.ID = TextureID; packet.ImageID.Packet = packetNumber; packet.ImageData.Data = imageData; m_udp.SendPacket(m_agent, packet, ThrottleCategory.Texture, false); }
/// <summary> /// Handles the remaining Image data that did not fit in the initial ImageData packet /// </summary> private void ImagePacketHandler(Packet packet, Simulator simulator) { ImagePacketPacket image = (ImagePacketPacket)packet; ImageDownload transfer = null; lock (Transfers) { if (Transfers.ContainsKey(image.ImageID.ID)) { transfer = (ImageDownload)Transfers[image.ImageID.ID]; if (transfer.Size == 0) { // We haven't received the header yet, block until it's received or times out transfer.HeaderReceivedEvent.WaitOne(1000 * 20, false); if (transfer.Size == 0) { Client.Log("Timed out while waiting for the image header to download for " + transfer.ID.ToString(), Helpers.LogLevel.Warning); transfer.Success = false; Transfers.Remove(transfer.ID); goto Callback; } } // The header is downloaded, we can insert this data in to the proper position Array.Copy(image.ImageData.Data, 0, transfer.AssetData, transfer.InitialDataSize + (1000 * (image.ImageID.Packet - 1)), image.ImageData.Data.Length); transfer.Transferred += image.ImageData.Data.Length; //Client.DebugLog("Received " + image.ImageData.Data.Length + "/" + transfer.Transferred + // "/" + transfer.Size + " bytes for image " + image.ImageID.ID.ToString()); // Check if we downloaded the full image if (transfer.Transferred >= transfer.Size) { transfer.Success = true; Transfers.Remove(transfer.ID); } } } Callback: if (transfer != null && OnImageReceived != null && (transfer.Transferred >= transfer.Size || transfer.Size == 0)) { try { OnImageReceived(transfer, new AssetTexture(transfer.AssetData)); } catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); } } }
/// <summary> /// Handles the remaining Image data that did not fit in the initial ImageData packet /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> public void ImagePacketCallbackHandler(Packet packet, Simulator simulator) { #if DEBUG_PACKETS Console.WriteLine(packet); #endif ImagePacketPacket reply = (ImagePacketPacket)packet; LLUUID ImageID = reply.ImageID.ID; // Lookup the request for this packet TransferRequest tr; lock (htDownloadRequests) { tr = (TransferRequest)htDownloadRequests[ImageID]; } if (tr == null) { // Received a packet that doesn't belong to any requests in our queue, strange... return; } // TODO: Received data should probably be put into a temporary collection that's indected by ImageID.Packet // then once we've received all data packets, it should be re-assembled into a complete array and marked // completed. // FIXME: Sometimes this gets called before ImageDataCallbackHandler, when that // happens tr.AssetData will be null. Implimenting the above TODO should fix this. // Wait until we've received the header packet for this image, which creates the AssetData array tr.ReceivedHeaderPacket.WaitOne(); // Add this packet's data to the request. Array.Copy(reply.ImageData.Data, 0, tr.AssetData, tr.BaseDataReceived + (1000 * (reply.ImageID.Packet - 1)), reply.ImageData.Data.Length); tr.Received += (uint)reply.ImageData.Data.Length; // If we've gotten all the data, mark it completed. if (tr.Received >= tr.Size) { tr.Status = true; tr.Completed.Set(); // Fire off image downloaded event CacheImage(ImageID, tr.AssetData); FireImageRetrieved(ImageID, tr.AssetData, false); } }
/// <summary> /// Handles the remaining Image data that did not fit in the initial ImageData packet /// </summary> /// <param name="sender">The sender</param> /// <param name="e">The EventArgs object containing the packet data</param> protected void ImagePacketHandler(object sender, PacketReceivedEventArgs e) { ImagePacketPacket image = (ImagePacketPacket)e.Packet; TaskInfo task; if (TryGetTransferValue(image.ImageID.ID, out task)) { if (task.Transfer.Size == 0) { // We haven't received the header yet, block until it's received or times out task.Transfer.HeaderReceivedEvent.WaitOne(1000 * 5, false); if (task.Transfer.Size == 0) { Logger.Log("Timed out while waiting for the image header to download for " + task.Transfer.ID, Helpers.LogLevel.Warning, _Client); RemoveTransfer(task.Transfer.ID); resetEvents[task.RequestSlot].Set(); // free up request slot foreach (TextureDownloadCallback callback in task.Callbacks) { callback(TextureRequestState.Timeout, new AssetTexture(task.RequestID, task.Transfer.AssetData)); } return; } } // The header is downloaded, we can insert this data in to the proper position // Only insert if we haven't seen this packet before lock (task.Transfer) { if (!task.Transfer.PacketsSeen.ContainsKey(image.ImageID.Packet)) { task.Transfer.PacketsSeen[image.ImageID.Packet] = image.ImageID.Packet; Buffer.BlockCopy(image.ImageData.Data, 0, task.Transfer.AssetData, task.Transfer.InitialDataSize + (1000 * (image.ImageID.Packet - 1)), image.ImageData.Data.Length); task.Transfer.Transferred += image.ImageData.Data.Length; } } task.Transfer.TimeSinceLastPacket = 0; if (task.Transfer.Transferred >= task.Transfer.Size) { #if DEBUG_TIMING DateTime stopTime = DateTime.UtcNow; TimeSpan requestDuration = stopTime - task.StartTime; TimeSpan networkDuration = stopTime - task.NetworkTime; TotalTime += requestDuration; NetworkTime += networkDuration; TotalBytes += task.Transfer.Size; Logger.Log( String.Format( "Transfer Complete {0} [{1}] Total Request Time: {2}, Download Time {3}, Network {4}Kb/sec, Image Size {5} bytes", task.RequestID, task.RequestSlot, requestDuration, networkDuration, Math.Round(task.Transfer.Size / networkDuration.TotalSeconds / 60, 2), task.Transfer.Size), Helpers.LogLevel.Debug); #endif task.Transfer.Success = true; RemoveTransfer(task.Transfer.ID); resetEvents[task.RequestSlot].Set(); // free up request slot _Client.Assets.Cache.SaveAssetToCache(task.RequestID, task.Transfer.AssetData); foreach (TextureDownloadCallback callback in task.Callbacks) { callback(TextureRequestState.Finished, new AssetTexture(task.RequestID, task.Transfer.AssetData)); } _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, task.Transfer.Size); } else { if (task.ReportProgress) { foreach (TextureDownloadCallback callback in task.Callbacks) { callback(TextureRequestState.Progress, new AssetTexture(task.RequestID, task.Transfer.AssetData)); } } _Client.Assets.FireImageProgressEvent(task.RequestID, task.Transfer.Transferred, task.Transfer.Size); } } }
void SendTexture(Agent agent, AssetTexture texture, int discardLevel, int packet, float priority) { ImageDownload download = new ImageDownload(texture, agent, discardLevel, priority, packet); Logger.DebugLog(String.Format( "[Periscope] Starting new texture transfer for {0}, DiscardLevel: {1}, Priority: {2}, Start: {3}, End: {4}, Total: {5}", texture.AssetID, discardLevel, priority, download.CurrentPacket, download.StopPacket, download.TexturePacketCount())); // Send initial data ImageDataPacket data = new ImageDataPacket(); data.ImageID.Codec = (byte)ImageCodec.J2C; data.ImageID.ID = download.Texture.AssetID; data.ImageID.Packets = (ushort)download.TexturePacketCount(); data.ImageID.Size = (uint)download.Texture.AssetData.Length; // The first bytes of the image are always sent in the ImageData packet data.ImageData = new ImageDataPacket.ImageDataBlock(); int imageDataSize = (download.Texture.AssetData.Length >= ImageDownload.FIRST_IMAGE_PACKET_SIZE) ? ImageDownload.FIRST_IMAGE_PACKET_SIZE : download.Texture.AssetData.Length; try { data.ImageData.Data = new byte[imageDataSize]; Buffer.BlockCopy(download.Texture.AssetData, 0, data.ImageData.Data, 0, imageDataSize); } catch (Exception ex) { Logger.Log(String.Format("{0}: imageDataSize={1}", ex.Message, imageDataSize), Helpers.LogLevel.Error); } server.UDP.SendPacket(agent.Avatar.ID, data, PacketCategory.Texture); // Check if ImagePacket packets need to be sent to complete this transfer if (download.CurrentPacket <= download.StopPacket) { // Insert this download into the dictionary lock (currentDownloads) currentDownloads[texture.AssetID] = download; // Send all of the remaining packets ThreadPool.QueueUserWorkItem( delegate(object obj) { while (download.CurrentPacket <= download.StopPacket) { if (download.Priority == 0.0f && download.DiscardLevel == -1) break; lock (download) { int imagePacketSize = (download.CurrentPacket == download.TexturePacketCount() - 1) ? download.LastPacketSize() : ImageDownload.IMAGE_PACKET_SIZE; ImagePacketPacket transfer = new ImagePacketPacket(); transfer.ImageID.ID = texture.AssetID; transfer.ImageID.Packet = (ushort)download.CurrentPacket; transfer.ImageData.Data = new byte[imagePacketSize]; try { Buffer.BlockCopy(download.Texture.AssetData, download.CurrentBytePosition(), transfer.ImageData.Data, 0, imagePacketSize); } catch (Exception ex) { Logger.Log(String.Format( "{0}: CurrentBytePosition()={1}, AssetData.Length={2} imagePacketSize={3}", ex.Message, download.CurrentBytePosition(), download.Texture.AssetData.Length, imagePacketSize), Helpers.LogLevel.Error); } server.UDP.SendPacket(agent.Avatar.ID, transfer, PacketCategory.Texture); ++download.CurrentPacket; } } Logger.DebugLog("Completed image transfer for " + texture.AssetID.ToString()); // Transfer is complete, remove the reference lock (currentDownloads) currentDownloads.Remove(texture.AssetID); } ); } }
void RequestImageHandler(Packet packet, Agent agent) { RequestImagePacket request = (RequestImagePacket)packet; for (int i = 0; i < request.RequestImage.Length; i++) { RequestImagePacket.RequestImageBlock block = request.RequestImage[i]; ImageDownload download; bool downloadFound = CurrentDownloads.TryGetValue(block.Image, out download); if (downloadFound) { lock (download) { if (block.DiscardLevel == -1 && block.DownloadPriority == 0.0f) { Logger.DebugLog(String.Format("Image download {0} is aborting", block.Image)); } else { if (block.DiscardLevel < download.DiscardLevel) { Logger.DebugLog(String.Format("Image download {0} is changing from DiscardLevel {1} to {2}", block.Image, download.DiscardLevel, block.DiscardLevel)); } if (block.DownloadPriority != download.Priority) { Logger.DebugLog(String.Format("Image download {0} is changing from Priority {1} to {2}", block.Image, download.Priority, block.DownloadPriority)); } if (block.Packet != download.CurrentPacket) { Logger.DebugLog(String.Format("Image download {0} is changing from Packet {1} to {2}", block.Image, download.CurrentPacket, block.Packet)); } } // Update download download.Update(block.DiscardLevel, block.DownloadPriority, (int)block.Packet); } } else if (block.DiscardLevel == -1 && block.DownloadPriority == 0.0f) { // Aborting a download we are not tracking, ignore Logger.DebugLog(String.Format("Aborting an image download for untracked image " + block.Image.ToString())); } else { bool bake = ((ImageType)block.Type == ImageType.Baked); // New download, check if we have this image Asset asset; if (server.Assets.TryGetAsset(block.Image, out asset) && asset is AssetTexture) { download = new ImageDownload((AssetTexture)asset, block.DiscardLevel, block.DownloadPriority, (int)block.Packet); Logger.DebugLog(String.Format( "Starting new download for {0}, DiscardLevel: {1}, Priority: {2}, Start: {3}, End: {4}, Total: {5}", block.Image, block.DiscardLevel, block.DownloadPriority, download.CurrentPacket, download.StopPacket, download.TexturePacketCount())); // Send initial data ImageDataPacket data = new ImageDataPacket(); data.ImageID.Codec = (byte)ImageCodec.J2C; data.ImageID.ID = download.Texture.AssetID; data.ImageID.Packets = (ushort)download.TexturePacketCount(); data.ImageID.Size = (uint)download.Texture.AssetData.Length; // The first bytes of the image are always sent in the ImageData packet data.ImageData = new ImageDataPacket.ImageDataBlock(); int imageDataSize = (download.Texture.AssetData.Length >= ImageDownload.FIRST_IMAGE_PACKET_SIZE) ? ImageDownload.FIRST_IMAGE_PACKET_SIZE : download.Texture.AssetData.Length; data.ImageData.Data = new byte[imageDataSize]; Buffer.BlockCopy(download.Texture.AssetData, 0, data.ImageData.Data, 0, imageDataSize); server.UDP.SendPacket(agent.AgentID, data, PacketCategory.Texture); // Check if ImagePacket packets need to be sent to complete this transfer if (download.CurrentPacket <= download.StopPacket) { // Insert this download into the dictionary lock (CurrentDownloads) CurrentDownloads[block.Image] = download; // Send all of the remaining packets ThreadPool.QueueUserWorkItem( delegate(object obj) { while (download.CurrentPacket <= download.StopPacket) { if (download.Priority == 0.0f && download.DiscardLevel == -1) { break; } lock (download) { int imagePacketSize = (download.CurrentPacket == download.TexturePacketCount() - 1) ? download.LastPacketSize() : ImageDownload.IMAGE_PACKET_SIZE; ImagePacketPacket transfer = new ImagePacketPacket(); transfer.ImageID.ID = block.Image; transfer.ImageID.Packet = (ushort)download.CurrentPacket; transfer.ImageData.Data = new byte[imagePacketSize]; Buffer.BlockCopy(download.Texture.AssetData, download.CurrentBytePosition(), transfer.ImageData.Data, 0, imagePacketSize); server.UDP.SendPacket(agent.AgentID, transfer, PacketCategory.Texture); ++download.CurrentPacket; } } Logger.DebugLog("Completed image transfer for " + block.Image.ToString()); // Transfer is complete, remove the reference lock (CurrentDownloads) CurrentDownloads.Remove(block.Image); } ); } } else { Logger.Log("Request for a missing texture " + block.Image.ToString(), Helpers.LogLevel.Warning); ImageNotInDatabasePacket notfound = new ImageNotInDatabasePacket(); notfound.ImageID.ID = block.Image; server.UDP.SendPacket(agent.AgentID, notfound, PacketCategory.Texture); } } } }
/// <summary> /// /// </summary> private void ProcessTextureQueue() { if (this.TextureRequests.Count == 0) { //no requests waiting return; } int num; if (this.TextureRequests.Count < 5) { //lower than 5 so do all of them num = this.TextureRequests.Count; } else { num = 5; } AssetRequest req; for (int i = 0; i < num; i++) { req = (AssetRequest)this.TextureRequests[i]; if (req.PacketCounter != req.NumPackets) { // if (req.ImageInfo.FullID == new LLUUID("00000000-0000-0000-5005-000000000005")) if (req.PacketCounter == 0) { //first time for this request so send imagedata packet if (req.NumPackets == 1) { //only one packet so send whole file ImageDataPacket im = new ImageDataPacket(); im.ImageID.Packets = 1; im.ImageID.ID = req.ImageInfo.FullID; im.ImageID.Size = (uint)req.ImageInfo.Data.Length; im.ImageData.Data = req.ImageInfo.Data; im.ImageID.Codec = 2; req.RequestUser.OutPacket(im); req.PacketCounter++; //req.ImageInfo.l= time; //System.Console.WriteLine("sent texture: "+req.image_info.FullID); } else { //more than one packet so split file up ImageDataPacket im = new ImageDataPacket(); im.ImageID.Packets = (ushort)req.NumPackets; im.ImageID.ID = req.ImageInfo.FullID; im.ImageID.Size = (uint)req.ImageInfo.Data.Length; im.ImageData.Data = new byte[600]; Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600); im.ImageID.Codec = 2; req.RequestUser.OutPacket(im); req.PacketCounter++; //req.ImageInfo.last_used = time; //System.Console.WriteLine("sent first packet of texture: } } else { //send imagepacket //more than one packet so split file up ImagePacketPacket im = new ImagePacketPacket(); im.ImageID.Packet = (ushort)req.PacketCounter; im.ImageID.ID = req.ImageInfo.FullID; int size = req.ImageInfo.Data.Length - 600 - 1000 * (req.PacketCounter - 1); if (size > 1000) size = 1000; im.ImageData.Data = new byte[size]; Array.Copy(req.ImageInfo.Data, 600 + 1000 * (req.PacketCounter - 1), im.ImageData.Data, 0, size); req.RequestUser.OutPacket(im); req.PacketCounter++; //req.ImageInfo.last_used = time; //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID); } } } //remove requests that have been completed int count = 0; for (int i = 0; i < num; i++) { if (this.TextureRequests.Count > count) { req = (AssetRequest)this.TextureRequests[count]; if (req.PacketCounter == req.NumPackets) { this.TextureRequests.Remove(req); } else { count++; } } } }
public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) { ImagePacketPacket im = new ImagePacketPacket(); im.Header.Reliable = true; im.ImageID.Packet = partNumber; im.ImageID.ID = imageUuid; im.ImageData.Data = imageData; //OutPacket(im, ThrottleOutPacketType.Texture); proxy.InjectPacket(im, Direction.Incoming); }
/// <summary> /// /// </summary> private void ProcessTextureQueue() { if (this.TextureRequests.Count == 0) { //no requests waiting return; } int num; if (this.TextureRequests.Count < 5) { //lower than 5 so do all of them num = this.TextureRequests.Count; } else { num = 5; } AssetRequest req; for (int i = 0; i < num; i++) { req = (AssetRequest)this.TextureRequests[i]; if (req.PacketCounter != req.NumPackets) { // if (req.ImageInfo.FullID == new LLUUID("00000000-0000-0000-5005-000000000005")) if (req.PacketCounter == 0) { //first time for this request so send imagedata packet if (req.NumPackets == 1) { //only one packet so send whole file ImageDataPacket im = new ImageDataPacket(); im.ImageID.Packets = 1; im.ImageID.ID = req.ImageInfo.FullID; im.ImageID.Size = (uint)req.ImageInfo.Data.Length; im.ImageData.Data = req.ImageInfo.Data; im.ImageID.Codec = 2; req.RequestUser.OutPacket(im); req.PacketCounter++; //req.ImageInfo.l= time; //System.Console.WriteLine("sent texture: "+req.image_info.FullID); } else { //more than one packet so split file up ImageDataPacket im = new ImageDataPacket(); im.ImageID.Packets = (ushort)req.NumPackets; im.ImageID.ID = req.ImageInfo.FullID; im.ImageID.Size = (uint)req.ImageInfo.Data.Length; im.ImageData.Data = new byte[600]; Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600); im.ImageID.Codec = 2; req.RequestUser.OutPacket(im); req.PacketCounter++; //req.ImageInfo.last_used = time; //System.Console.WriteLine("sent first packet of texture: } } else { //send imagepacket //more than one packet so split file up ImagePacketPacket im = new ImagePacketPacket(); im.ImageID.Packet = (ushort)req.PacketCounter; im.ImageID.ID = req.ImageInfo.FullID; int size = req.ImageInfo.Data.Length - 600 - 1000 * (req.PacketCounter - 1); if (size > 1000) { size = 1000; } im.ImageData.Data = new byte[size]; Array.Copy(req.ImageInfo.Data, 600 + 1000 * (req.PacketCounter - 1), im.ImageData.Data, 0, size); req.RequestUser.OutPacket(im); req.PacketCounter++; //req.ImageInfo.last_used = time; //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID); } } } //remove requests that have been completed int count = 0; for (int i = 0; i < num; i++) { if (this.TextureRequests.Count > count) { req = (AssetRequest)this.TextureRequests[count]; if (req.PacketCounter == req.NumPackets) { this.TextureRequests.Remove(req); } else { count++; } } } }