Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 2288 → Rev 2289

/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/Cache.cs
0,0 → 1,305

namespace GMap.NET.Internals
{
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using GMap.NET.CacheProviders;
using System.Security.Cryptography;
 
internal class CacheLocator
{
private static string location;
public static string Location
{
get
{
if(string.IsNullOrEmpty(location))
{
Reset();
}
 
return location;
}
set
{
if(string.IsNullOrEmpty(value)) // setting to null resets to default
{
Reset();
}
else
{
location = value;
}
 
if(Delay)
{
Cache.Instance.CacheLocation = location;
}
}
}
 
static void Reset()
{
string appDataLocation = GetApplicationDataFolderPath();
 
#if !PocketPC
// http://greatmaps.codeplex.com/discussions/403151
// by default Network Service don't have disk write access
if(string.IsNullOrEmpty(appDataLocation))
{
GMaps.Instance.Mode = AccessMode.ServerOnly;
GMaps.Instance.UseDirectionsCache = false;
GMaps.Instance.UseGeocoderCache = false;
GMaps.Instance.UsePlacemarkCache = false;
GMaps.Instance.UseRouteCache = false;
GMaps.Instance.UseUrlCache = false;
}
else
#endif
{
Location = appDataLocation;
}
}
 
public static string GetApplicationDataFolderPath()
{
#if !PocketPC
bool isSystem = false;
try
{
using(var identity = System.Security.Principal.WindowsIdentity.GetCurrent())
{
if(identity != null)
{
isSystem = identity.IsSystem;
}
}
}
catch(Exception ex)
{
Trace.WriteLine("SQLitePureImageCache, WindowsIdentity.GetCurrent: " + ex);
}
 
string path = string.Empty;
 
// https://greatmaps.codeplex.com/workitem/16112
if(isSystem)
{
path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData);
}
else
{
path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
}
#else
path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
#endif
 
if(!string.IsNullOrEmpty(path))
{
path += Path.DirectorySeparatorChar + "GMap.NET" + Path.DirectorySeparatorChar;
}
 
return path;
}
 
public static bool Delay = false;
}
 
/// <summary>
/// cache system for tiles, geocoding, etc...
/// </summary>
internal class Cache : Singleton<Cache>
{
/// <summary>
/// abstract image cache
/// </summary>
public PureImageCache ImageCache;
 
/// <summary>
/// second level abstract image cache
/// </summary>
public PureImageCache ImageCacheSecond;
 
string cache;
 
/// <summary>
/// local cache location
/// </summary>
public string CacheLocation
{
get
{
return cache;
}
set
{
cache = value;
#if SQLite
if(ImageCache is SQLitePureImageCache)
{
(ImageCache as SQLitePureImageCache).CacheLocation = value;
}
#else
if(ImageCache is MsSQLCePureImageCache)
{
(ImageCache as MsSQLCePureImageCache).CacheLocation = value;
}
#endif
CacheLocator.Delay = true;
}
}
 
public Cache()
{
#region singleton check
if(Instance != null)
{
throw (new System.Exception("You have tried to create a new singleton class where you should have instanced it. Replace your \"new class()\" with \"class.Instance\""));
}
#endregion
 
#if SQLite
ImageCache = new SQLitePureImageCache();
#else
// you can use $ms stuff if you like too ;}
ImageCache = new MsSQLCePureImageCache();
#endif
 
#if PocketPC
// use sd card if exist for cache
string sd = Native.GetRemovableStorageDirectory();
if(!string.IsNullOrEmpty(sd))
{
CacheLocation = sd + Path.DirectorySeparatorChar + "GMap.NET" + Path.DirectorySeparatorChar;
}
else
#endif
{
#if PocketPC
CacheLocation = CacheLocator.Location;
#else
string newCache = CacheLocator.Location;
 
string oldCache = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData) + Path.DirectorySeparatorChar + "GMap.NET" + Path.DirectorySeparatorChar;
 
// move database to non-roaming user directory
if(Directory.Exists(oldCache))
{
try
{
if(Directory.Exists(newCache))
{
Directory.Delete(oldCache, true);
}
else
{
Directory.Move(oldCache, newCache);
}
CacheLocation = newCache;
}
catch(Exception ex)
{
CacheLocation = oldCache;
Trace.WriteLine("SQLitePureImageCache, moving data: " + ex.ToString());
}
}
else
{
CacheLocation = newCache;
}
#endif
}
}
 
#region -- etc cache --
 
static readonly SHA1CryptoServiceProvider HashProvider = new SHA1CryptoServiceProvider();
 
void ConvertToHash(ref string s)
{
s = BitConverter.ToString(HashProvider.ComputeHash(Encoding.Unicode.GetBytes(s)));
}
 
public void SaveContent(string url, CacheType type, string content)
{
try
{
ConvertToHash(ref url);
 
string dir = Path.Combine(cache, type.ToString()) + Path.DirectorySeparatorChar;
 
// precrete dir
if(!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
 
string file = dir + url + ".txt";
 
using(StreamWriter writer = new StreamWriter(file, false, Encoding.UTF8))
{
writer.Write(content);
}
}
catch(Exception ex)
{
Debug.WriteLine("SaveContent: " + ex);
}
}
 
public string GetContent(string url, CacheType type, TimeSpan stayInCache)
{
string ret = null;
 
try
{
ConvertToHash(ref url);
 
string dir = Path.Combine(cache, type.ToString()) + Path.DirectorySeparatorChar;
string file = dir + url + ".txt";
 
if(File.Exists(file))
{
var writeTime = File.GetLastWriteTime(file);
if (DateTime.Now - writeTime < stayInCache)
{
using (StreamReader r = new StreamReader(file, Encoding.UTF8))
{
ret = r.ReadToEnd();
}
}
else
{
File.Delete(file);
}
}
}
catch(Exception ex)
{
ret = null;
Debug.WriteLine("GetContent: " + ex);
}
 
return ret;
}
 
public string GetContent(string url, CacheType type)
{
return GetContent(url, type, TimeSpan.FromDays(88));
}
 
#endregion
}
 
internal enum CacheType
{
GeocoderCache,
PlacemarkCache,
RouteCache,
UrlCache,
DirectionsCache,
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/CacheQueueItem.cs
0,0 → 1,40

namespace GMap.NET.Internals
{
using System.IO;
using System;
 
/// <summary>
/// cache queue item
/// </summary>
internal struct CacheQueueItem
{
public RawTile Tile;
public byte[] Img;
public CacheUsage CacheType;
 
public CacheQueueItem(RawTile tile, byte[] Img, CacheUsage cacheType)
{
this.Tile = tile;
this.Img = Img;
this.CacheType = cacheType;
}
 
public override string ToString()
{
return Tile + ", CacheType:" + CacheType;
}
 
public void Clear()
{
Img = null;
}
}
 
internal enum CacheUsage
{
First = 2,
Second = 4,
Both = First | Second
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/Core.cs
0,0 → 1,1400

namespace GMap.NET.Internals
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using GMap.NET.Projections;
using System.IO;
using GMap.NET.MapProviders;
using System.ComponentModel;
 
#if NET40
using System.Collections.Concurrent;
using System.Threading.Tasks;
#endif
 
#if PocketPC
using OpenNETCF.ComponentModel;
using OpenNETCF.Threading;
using Thread=OpenNETCF.Threading.Thread2;
#endif
 
/// <summary>
/// internal map control core
/// </summary>
internal class Core : IDisposable
{
public PointLatLng position;
public GPoint positionPixel;
 
public GPoint renderOffset;
public GPoint centerTileXYLocation;
public GPoint centerTileXYLocationLast;
public GPoint dragPoint;
public GPoint compensationOffset;
 
public GPoint mouseDown;
public GPoint mouseCurrent;
public GPoint mouseLastZoom;
 
public MouseWheelZoomType MouseWheelZoomType = MouseWheelZoomType.MousePositionAndCenter;
public bool MouseWheelZoomEnabled = true;
 
public PointLatLng? LastLocationInBounds = null;
public bool VirtualSizeEnabled = false;
 
public GSize sizeOfMapArea;
public GSize minOfTiles;
public GSize maxOfTiles;
 
public GRect tileRect;
public GRect tileRectBearing;
//public GRect currentRegion;
public float bearing = 0;
public bool IsRotated = false;
 
public bool fillEmptyTiles = true;
 
public TileMatrix Matrix = new TileMatrix();
 
public List<DrawTile> tileDrawingList = new List<DrawTile>();
public FastReaderWriterLock tileDrawingListLock = new FastReaderWriterLock();
 
#if !NET40
public readonly Stack<LoadTask> tileLoadQueue = new Stack<LoadTask>();
#endif
 
#if !PocketPC
static readonly int GThreadPoolSize = 4;
#else
static readonly int GThreadPoolSize = 2;
#endif
 
DateTime LastTileLoadStart = DateTime.Now;
DateTime LastTileLoadEnd = DateTime.Now;
internal volatile bool IsStarted = false;
int zoom;
 
internal double scaleX = 1;
internal double scaleY = 1;
 
internal int maxZoom = 2;
internal int minZoom = 2;
internal int Width;
internal int Height;
 
internal int pxRes100m; // 100 meters
internal int pxRes1000m; // 1km
internal int pxRes10km; // 10km
internal int pxRes100km; // 100km
internal int pxRes1000km; // 1000km
internal int pxRes5000km; // 5000km
 
/// <summary>
/// is user dragging map
/// </summary>
public bool IsDragging = false;
 
public Core()
{
Provider = EmptyProvider.Instance;
}
 
/// <summary>
/// map zoom
/// </summary>
public int Zoom
{
get
{
return zoom;
}
set
{
if (zoom != value && !IsDragging)
{
zoom = value;
 
minOfTiles = Provider.Projection.GetTileMatrixMinXY(value);
maxOfTiles = Provider.Projection.GetTileMatrixMaxXY(value);
 
positionPixel = Provider.Projection.FromLatLngToPixel(Position, value);
 
if (IsStarted)
{
CancelAsyncTasks();
 
Matrix.ClearLevelsBelove(zoom - LevelsKeepInMemmory);
Matrix.ClearLevelsAbove(zoom + LevelsKeepInMemmory);
 
lock (FailedLoads)
{
FailedLoads.Clear();
RaiseEmptyTileError = true;
}
 
GoToCurrentPositionOnZoom();
UpdateBounds();
 
if (OnMapZoomChanged != null)
{
OnMapZoomChanged();
}
}
}
}
}
 
/// <summary>
/// current marker position in pixel coordinates
/// </summary>
public GPoint PositionPixel
{
get
{
return positionPixel;
}
}
 
/// <summary>
/// current marker position
/// </summary>
public PointLatLng Position
{
get
{
 
return position;
}
set
{
position = value;
positionPixel = Provider.Projection.FromLatLngToPixel(value, Zoom);
 
if (IsStarted)
{
if (!IsDragging)
{
GoToCurrentPosition();
}
 
if (OnCurrentPositionChanged != null)
OnCurrentPositionChanged(position);
}
}
}
 
public GMapProvider provider;
public GMapProvider Provider
{
get
{
return provider;
}
set
{
if (provider == null || !provider.Equals(value))
{
bool diffProjection = (provider == null || provider.Projection != value.Projection);
 
provider = value;
 
if (!provider.IsInitialized)
{
provider.IsInitialized = true;
provider.OnInitialized();
}
 
if (provider.Projection != null && diffProjection)
{
tileRect = new GRect(GPoint.Empty, Provider.Projection.TileSize);
tileRectBearing = tileRect;
if (IsRotated)
{
tileRectBearing.Inflate(1, 1);
}
 
minOfTiles = Provider.Projection.GetTileMatrixMinXY(Zoom);
maxOfTiles = Provider.Projection.GetTileMatrixMaxXY(Zoom);
positionPixel = Provider.Projection.FromLatLngToPixel(Position, Zoom);
}
 
if (IsStarted)
{
CancelAsyncTasks();
if (diffProjection)
{
OnMapSizeChanged(Width, Height);
}
ReloadMap();
 
if (minZoom < provider.MinZoom)
{
minZoom = provider.MinZoom;
}
 
//if(provider.MaxZoom.HasValue && maxZoom > provider.MaxZoom)
//{
// maxZoom = provider.MaxZoom.Value;
//}
 
zoomToArea = true;
 
if (provider.Area.HasValue && !provider.Area.Value.Contains(Position))
{
SetZoomToFitRect(provider.Area.Value);
zoomToArea = false;
}
 
if (OnMapTypeChanged != null)
{
OnMapTypeChanged(value);
}
}
}
}
}
 
internal bool zoomToArea = true;
 
/// <summary>
/// sets zoom to max to fit rect
/// </summary>
/// <param name="rect"></param>
/// <returns></returns>
public bool SetZoomToFitRect(RectLatLng rect)
{
int mmaxZoom = GetMaxZoomToFitRect(rect);
if (mmaxZoom > 0)
{
PointLatLng center = new PointLatLng(rect.Lat - (rect.HeightLat / 2), rect.Lng + (rect.WidthLng / 2));
Position = center;
 
if (mmaxZoom > maxZoom)
{
mmaxZoom = maxZoom;
}
 
if (Zoom != mmaxZoom)
{
Zoom = (int)mmaxZoom;
}
 
return true;
}
return false;
}
 
/// <summary>
/// is polygons enabled
/// </summary>
public bool PolygonsEnabled = true;
 
/// <summary>
/// is routes enabled
/// </summary>
public bool RoutesEnabled = true;
 
/// <summary>
/// is markers enabled
/// </summary>
public bool MarkersEnabled = true;
 
/// <summary>
/// can user drag map
/// </summary>
public bool CanDragMap = true;
 
/// <summary>
/// retry count to get tile
/// </summary>
#if !PocketPC
public int RetryLoadTile = 0;
#else
public int RetryLoadTile = 1;
#endif
 
/// <summary>
/// how many levels of tiles are staying decompresed in memory
/// </summary>
#if !PocketPC
public int LevelsKeepInMemmory = 5;
#else
public int LevelsKeepInMemmory = 1;
#endif
 
/// <summary>
/// map render mode
/// </summary>
public RenderMode RenderMode = RenderMode.GDI_PLUS;
 
/// <summary>
/// occurs when current position is changed
/// </summary>
public event PositionChanged OnCurrentPositionChanged;
 
/// <summary>
/// occurs when tile set load is complete
/// </summary>
public event TileLoadComplete OnTileLoadComplete;
 
/// <summary>
/// occurs when tile set is starting to load
/// </summary>
public event TileLoadStart OnTileLoadStart;
 
/// <summary>
/// occurs on empty tile displayed
/// </summary>
public event EmptyTileError OnEmptyTileError;
 
/// <summary>
/// occurs on map drag
/// </summary>
public event MapDrag OnMapDrag;
 
/// <summary>
/// occurs on map zoom changed
/// </summary>
public event MapZoomChanged OnMapZoomChanged;
 
/// <summary>
/// occurs on map type changed
/// </summary>
public event MapTypeChanged OnMapTypeChanged;
 
readonly List<Thread> GThreadPool = new List<Thread>();
// ^
// should be only one pool for multiply controls, any ideas how to fix?
//static readonly List<Thread> GThreadPool = new List<Thread>();
 
// windows forms or wpf
internal string SystemType;
 
internal static int instances = 0;
 
BackgroundWorker invalidator;
 
public BackgroundWorker OnMapOpen()
{
if (!IsStarted)
{
int x = Interlocked.Increment(ref instances);
Debug.WriteLine("OnMapOpen: " + x);
 
IsStarted = true;
 
if (x == 1)
{
GMaps.Instance.noMapInstances = false;
}
 
GoToCurrentPosition();
 
invalidator = new BackgroundWorker();
invalidator.WorkerSupportsCancellation = true;
invalidator.WorkerReportsProgress = true;
invalidator.DoWork += new DoWorkEventHandler(invalidatorWatch);
invalidator.RunWorkerAsync();
 
//if(x == 1)
//{
// first control shown
//}
}
return invalidator;
}
 
public void OnMapClose()
{
Dispose();
}
 
internal readonly object invalidationLock = new object();
internal DateTime lastInvalidation = DateTime.Now;
 
void invalidatorWatch(object sender, DoWorkEventArgs e)
{
var w = sender as BackgroundWorker;
 
TimeSpan span = TimeSpan.FromMilliseconds(111);
int spanMs = (int)span.TotalMilliseconds;
bool skiped = false;
TimeSpan delta;
DateTime now = DateTime.Now;
 
while (Refresh != null && (!skiped && Refresh.WaitOne() || (Refresh.WaitOne(spanMs, false) || true)))
{
if (w.CancellationPending)
break;
 
now = DateTime.Now;
lock (invalidationLock)
{
delta = now - lastInvalidation;
}
 
if (delta > span)
{
lock (invalidationLock)
{
lastInvalidation = now;
}
skiped = false;
 
w.ReportProgress(1);
Debug.WriteLine("Invalidate delta: " + (int)delta.TotalMilliseconds + "ms");
}
else
{
skiped = true;
}
}
}
 
public void UpdateCenterTileXYLocation()
{
PointLatLng center = FromLocalToLatLng(Width / 2, Height / 2);
GPoint centerPixel = Provider.Projection.FromLatLngToPixel(center, Zoom);
centerTileXYLocation = Provider.Projection.FromPixelToTileXY(centerPixel);
}
 
public int vWidth = 800;
public int vHeight = 400;
 
public void OnMapSizeChanged(int width, int height)
{
this.Width = width;
this.Height = height;
 
if (IsRotated)
{
#if !PocketPC
int diag = (int)Math.Round(Math.Sqrt(Width * Width + Height * Height) / Provider.Projection.TileSize.Width, MidpointRounding.AwayFromZero);
#else
int diag = (int) Math.Round(Math.Sqrt(Width * Width + Height * Height) / Provider.Projection.TileSize.Width);
#endif
sizeOfMapArea.Width = 1 + (diag / 2);
sizeOfMapArea.Height = 1 + (diag / 2);
}
else
{
sizeOfMapArea.Width = 1 + (Width / Provider.Projection.TileSize.Width) / 2;
sizeOfMapArea.Height = 1 + (Height / Provider.Projection.TileSize.Height) / 2;
}
 
Debug.WriteLine("OnMapSizeChanged, w: " + width + ", h: " + height + ", size: " + sizeOfMapArea);
 
if (IsStarted)
{
UpdateBounds();
GoToCurrentPosition();
}
}
 
/// <summary>
/// gets current map view top/left coordinate, width in Lng, height in Lat
/// </summary>
/// <returns></returns>
public RectLatLng ViewArea
{
get
{
if (Provider.Projection != null)
{
var p = FromLocalToLatLng(0, 0);
var p2 = FromLocalToLatLng(Width, Height);
 
return RectLatLng.FromLTRB(p.Lng, p.Lat, p2.Lng, p2.Lat);
}
return RectLatLng.Empty;
}
}
 
/// <summary>
/// gets lat/lng from local control coordinates
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public PointLatLng FromLocalToLatLng(long x, long y)
{
GPoint p = new GPoint(x, y);
p.OffsetNegative(renderOffset);
p.Offset(compensationOffset);
 
return Provider.Projection.FromPixelToLatLng(p, Zoom);
}
 
/// <summary>
/// return local coordinates from lat/lng
/// </summary>
/// <param name="latlng"></param>
/// <returns></returns>
public GPoint FromLatLngToLocal(PointLatLng latlng)
{
GPoint pLocal = Provider.Projection.FromLatLngToPixel(latlng, Zoom);
pLocal.Offset(renderOffset);
pLocal.OffsetNegative(compensationOffset);
return pLocal;
}
 
/// <summary>
/// gets max zoom level to fit rectangle
/// </summary>
/// <param name="rect"></param>
/// <returns></returns>
public int GetMaxZoomToFitRect(RectLatLng rect)
{
int zoom = minZoom;
 
if (rect.HeightLat == 0 || rect.WidthLng == 0)
{
zoom = maxZoom / 2;
}
else
{
for (int i = (int)zoom; i <= maxZoom; i++)
{
GPoint p1 = Provider.Projection.FromLatLngToPixel(rect.LocationTopLeft, i);
GPoint p2 = Provider.Projection.FromLatLngToPixel(rect.LocationRightBottom, i);
 
if (((p2.X - p1.X) <= Width + 10) && (p2.Y - p1.Y) <= Height + 10)
{
zoom = i;
}
else
{
break;
}
}
}
 
return zoom;
}
 
/// <summary>
/// initiates map dragging
/// </summary>
/// <param name="pt"></param>
public void BeginDrag(GPoint pt)
{
dragPoint.X = pt.X - renderOffset.X;
dragPoint.Y = pt.Y - renderOffset.Y;
IsDragging = true;
}
 
/// <summary>
/// ends map dragging
/// </summary>
public void EndDrag()
{
IsDragging = false;
mouseDown = GPoint.Empty;
 
Refresh.Set();
}
 
/// <summary>
/// reloads map
/// </summary>
public void ReloadMap()
{
if (IsStarted)
{
Debug.WriteLine("------------------");
 
okZoom = 0;
skipOverZoom = 0;
 
CancelAsyncTasks();
 
Matrix.ClearAllLevels();
 
lock (FailedLoads)
{
FailedLoads.Clear();
RaiseEmptyTileError = true;
}
 
Refresh.Set();
 
UpdateBounds();
}
else
{
throw new Exception("Please, do not call ReloadMap before form is loaded, it's useless");
}
}
 
/// <summary>
/// moves current position into map center
/// </summary>
public void GoToCurrentPosition()
{
compensationOffset = positionPixel; // TODO: fix
 
// reset stuff
renderOffset = GPoint.Empty;
dragPoint = GPoint.Empty;
 
//var dd = new GPoint(-(CurrentPositionGPixel.X - Width / 2), -(CurrentPositionGPixel.Y - Height / 2));
//dd.Offset(compensationOffset);
 
var d = new GPoint(Width / 2, Height / 2);
 
this.Drag(d);
}
 
public bool MouseWheelZooming = false;
 
/// <summary>
/// moves current position into map center
/// </summary>
internal void GoToCurrentPositionOnZoom()
{
compensationOffset = positionPixel; // TODO: fix
 
// reset stuff
renderOffset = GPoint.Empty;
dragPoint = GPoint.Empty;
 
// goto location and centering
if (MouseWheelZooming)
{
if (MouseWheelZoomType != MouseWheelZoomType.MousePositionWithoutCenter)
{
GPoint pt = new GPoint(-(positionPixel.X - Width / 2), -(positionPixel.Y - Height / 2));
pt.Offset(compensationOffset);
renderOffset.X = pt.X - dragPoint.X;
renderOffset.Y = pt.Y - dragPoint.Y;
}
else // without centering
{
renderOffset.X = -positionPixel.X - dragPoint.X;
renderOffset.Y = -positionPixel.Y - dragPoint.Y;
renderOffset.Offset(mouseLastZoom);
renderOffset.Offset(compensationOffset);
}
}
else // use current map center
{
mouseLastZoom = GPoint.Empty;
 
GPoint pt = new GPoint(-(positionPixel.X - Width / 2), -(positionPixel.Y - Height / 2));
pt.Offset(compensationOffset);
renderOffset.X = pt.X - dragPoint.X;
renderOffset.Y = pt.Y - dragPoint.Y;
}
 
UpdateCenterTileXYLocation();
}
 
/// <summary>
/// darg map by offset in pixels
/// </summary>
/// <param name="offset"></param>
public void DragOffset(GPoint offset)
{
renderOffset.Offset(offset);
 
UpdateCenterTileXYLocation();
 
if (centerTileXYLocation != centerTileXYLocationLast)
{
centerTileXYLocationLast = centerTileXYLocation;
UpdateBounds();
}
 
{
LastLocationInBounds = Position;
 
IsDragging = true;
Position = FromLocalToLatLng((int)Width / 2, (int)Height / 2);
IsDragging = false;
}
 
if (OnMapDrag != null)
{
OnMapDrag();
}
}
 
/// <summary>
/// drag map
/// </summary>
/// <param name="pt"></param>
public void Drag(GPoint pt)
{
renderOffset.X = pt.X - dragPoint.X;
renderOffset.Y = pt.Y - dragPoint.Y;
 
UpdateCenterTileXYLocation();
 
if (centerTileXYLocation != centerTileXYLocationLast)
{
centerTileXYLocationLast = centerTileXYLocation;
UpdateBounds();
}
 
if (IsDragging)
{
LastLocationInBounds = Position;
Position = FromLocalToLatLng((int)Width / 2, (int)Height / 2);
 
if (OnMapDrag != null)
{
OnMapDrag();
}
}
}
 
/// <summary>
/// cancels tile loaders and bounds checker
/// </summary>
public void CancelAsyncTasks()
{
if (IsStarted)
{
#if NET40
//TODO: clear loading
#else
Monitor.Enter(tileLoadQueue);
try
{
tileLoadQueue.Clear();
}
finally
{
Monitor.Exit(tileLoadQueue);
}
#endif
}
}
 
bool RaiseEmptyTileError = false;
internal Dictionary<LoadTask, Exception> FailedLoads = new Dictionary<LoadTask, Exception>(new LoadTaskComparer());
 
internal static readonly int WaitForTileLoadThreadTimeout = 5 * 1000 * 60; // 5 min.
 
volatile int okZoom = 0;
volatile int skipOverZoom = 0;
 
#if NET40
static readonly BlockingCollection<LoadTask> tileLoadQueue4 = new BlockingCollection<LoadTask>(new ConcurrentStack<LoadTask>());
static List<Task> tileLoadQueue4Tasks;
static int loadWaitCount = 0;
void AddLoadTask(LoadTask t)
{
if (tileLoadQueue4Tasks == null)
{
lock (tileLoadQueue4)
{
if (tileLoadQueue4Tasks == null)
{
tileLoadQueue4Tasks = new List<Task>();
 
while (tileLoadQueue4Tasks.Count < GThreadPoolSize)
{
Debug.WriteLine("creating ProcessLoadTask: " + tileLoadQueue4Tasks.Count);
 
tileLoadQueue4Tasks.Add(Task.Factory.StartNew(delegate ()
{
string ctid = "ProcessLoadTask[" + Thread.CurrentThread.ManagedThreadId + "]";
Thread.CurrentThread.Name = ctid;
 
Debug.WriteLine(ctid + ": started");
do
{
if (tileLoadQueue4.Count == 0)
{
Debug.WriteLine(ctid + ": ready");
 
if (Interlocked.Increment(ref loadWaitCount) >= GThreadPoolSize)
{
Interlocked.Exchange(ref loadWaitCount, 0);
OnLoadComplete(ctid);
}
}
ProcessLoadTask(tileLoadQueue4.Take(), ctid);
}
while (!tileLoadQueue4.IsAddingCompleted);
 
Debug.WriteLine(ctid + ": exit");
 
}, TaskCreationOptions.LongRunning));
}
}
}
}
tileLoadQueue4.Add(t);
}
#else
byte loadWaitCount = 0;
 
void tileLoadThread()
{
LoadTask? task = null;
bool stop = false;
 
#if !PocketPC
Thread ct = Thread.CurrentThread;
string ctid = "Thread[" + ct.ManagedThreadId + "]";
#else
int ctid = 0;
#endif
while (!stop && IsStarted)
{
task = null;
 
Monitor.Enter(tileLoadQueue);
try
{
while (tileLoadQueue.Count == 0)
{
Debug.WriteLine(ctid + " - Wait " + loadWaitCount + " - " + DateTime.Now.TimeOfDay);
 
if (++loadWaitCount >= GThreadPoolSize)
{
loadWaitCount = 0;
OnLoadComplete(ctid);
}
 
if (!IsStarted || false == Monitor.Wait(tileLoadQueue, WaitForTileLoadThreadTimeout, false) || !IsStarted)
{
stop = true;
break;
}
}
 
if (IsStarted && !stop || tileLoadQueue.Count > 0)
{
task = tileLoadQueue.Pop();
}
}
finally
{
Monitor.Exit(tileLoadQueue);
}
 
if (task.HasValue && IsStarted)
{
ProcessLoadTask(task.Value, ctid);
}
}
 
#if !PocketPC
Monitor.Enter(tileLoadQueue);
try
{
Debug.WriteLine("Quit - " + ct.Name);
lock (GThreadPool)
{
GThreadPool.Remove(ct);
}
}
finally
{
Monitor.Exit(tileLoadQueue);
}
#endif
}
#endif
 
static void ProcessLoadTask(LoadTask task, string ctid)
{
try
{
#region -- execute --
 
var m = task.Core.Matrix.GetTileWithReadLock(task.Zoom, task.Pos);
if (!m.NotEmpty)
{
Debug.WriteLine(ctid + " - try load: " + task);
 
Tile t = new Tile(task.Zoom, task.Pos);
 
foreach (var tl in task.Core.provider.Overlays)
{
int retry = 0;
do
{
PureImage img = null;
Exception ex = null;
 
if (task.Zoom >= task.Core.provider.MinZoom && (!task.Core.provider.MaxZoom.HasValue || task.Zoom <= task.Core.provider.MaxZoom))
{
if (task.Core.skipOverZoom == 0 || task.Zoom <= task.Core.skipOverZoom)
{
// tile number inversion(BottomLeft -> TopLeft)
if (tl.InvertedAxisY)
{
img = GMaps.Instance.GetImageFrom(tl, new GPoint(task.Pos.X, task.Core.maxOfTiles.Height - task.Pos.Y), task.Zoom, out ex);
}
else // ok
{
img = GMaps.Instance.GetImageFrom(tl, task.Pos, task.Zoom, out ex);
}
}
}
 
if (img != null && ex == null)
{
if (task.Core.okZoom < task.Zoom)
{
task.Core.okZoom = task.Zoom;
task.Core.skipOverZoom = 0;
Debug.WriteLine("skipOverZoom disabled, okZoom: " + task.Core.okZoom);
}
}
else if (ex != null)
{
if ((task.Core.skipOverZoom != task.Core.okZoom) && (task.Zoom > task.Core.okZoom))
{
if (ex.Message.Contains("(404) Not Found"))
{
task.Core.skipOverZoom = task.Core.okZoom;
Debug.WriteLine("skipOverZoom enabled: " + task.Core.skipOverZoom);
}
}
}
 
// check for parent tiles if not found
if (img == null && task.Core.okZoom > 0 && task.Core.fillEmptyTiles && task.Core.Provider.Projection is MercatorProjection)
{
int zoomOffset = task.Zoom > task.Core.okZoom ? task.Zoom - task.Core.okZoom : 1;
long Ix = 0;
GPoint parentTile = GPoint.Empty;
 
while (img == null && zoomOffset < task.Zoom)
{
Ix = (long)Math.Pow(2, zoomOffset);
parentTile = new GMap.NET.GPoint((task.Pos.X / Ix), (task.Pos.Y / Ix));
img = GMaps.Instance.GetImageFrom(tl, parentTile, task.Zoom - zoomOffset++, out ex);
}
 
if (img != null)
{
// offsets in quadrant
long Xoff = Math.Abs(task.Pos.X - (parentTile.X * Ix));
long Yoff = Math.Abs(task.Pos.Y - (parentTile.Y * Ix));
 
img.IsParent = true;
img.Ix = Ix;
img.Xoff = Xoff;
img.Yoff = Yoff;
 
// wpf
//var geometry = new RectangleGeometry(new Rect(Core.tileRect.X + 0.6, Core.tileRect.Y + 0.6, Core.tileRect.Width + 0.6, Core.tileRect.Height + 0.6));
//var parentImgRect = new Rect(Core.tileRect.X - Core.tileRect.Width * Xoff + 0.6, Core.tileRect.Y - Core.tileRect.Height * Yoff + 0.6, Core.tileRect.Width * Ix + 0.6, Core.tileRect.Height * Ix + 0.6);
 
// gdi+
//System.Drawing.Rectangle dst = new System.Drawing.Rectangle((int)Core.tileRect.X, (int)Core.tileRect.Y, (int)Core.tileRect.Width, (int)Core.tileRect.Height);
//System.Drawing.RectangleF srcRect = new System.Drawing.RectangleF((float)(Xoff * (img.Img.Width / Ix)), (float)(Yoff * (img.Img.Height / Ix)), (img.Img.Width / Ix), (img.Img.Height / Ix));
}
}
 
if (img != null)
{
Debug.WriteLine(ctid + " - tile loaded: " + img.Data.Length / 1024 + "KB, " + task);
{
t.AddOverlay(img);
}
break;
}
else
{
if (ex != null)
{
lock (task.Core.FailedLoads)
{
if (!task.Core.FailedLoads.ContainsKey(task))
{
task.Core.FailedLoads.Add(task, ex);
 
if (task.Core.OnEmptyTileError != null)
{
if (!task.Core.RaiseEmptyTileError)
{
task.Core.RaiseEmptyTileError = true;
task.Core.OnEmptyTileError(task.Zoom, task.Pos);
}
}
}
}
}
 
if (task.Core.RetryLoadTile > 0)
{
Debug.WriteLine(ctid + " - ProcessLoadTask: " + task + " -> empty tile, retry " + retry);
{
Thread.Sleep(1111);
}
}
}
}
while (++retry < task.Core.RetryLoadTile);
}
 
if (t.HasAnyOverlays && task.Core.IsStarted)
{
task.Core.Matrix.SetTile(t);
}
else
{
t.Dispose();
}
}
 
#endregion
}
catch (Exception ex)
{
Debug.WriteLine(ctid + " - ProcessLoadTask: " + ex.ToString());
}
finally
{
if (task.Core.Refresh != null)
{
task.Core.Refresh.Set();
}
}
}
 
void OnLoadComplete(string ctid)
{
LastTileLoadEnd = DateTime.Now;
long lastTileLoadTimeMs = (long)(LastTileLoadEnd - LastTileLoadStart).TotalMilliseconds;
 
#region -- clear stuff--
if (IsStarted)
{
GMaps.Instance.MemoryCache.RemoveOverload();
 
tileDrawingListLock.AcquireReaderLock();
try
{
Matrix.ClearLevelAndPointsNotIn(Zoom, tileDrawingList);
}
finally
{
tileDrawingListLock.ReleaseReaderLock();
}
}
#endregion
 
UpdateGroundResolution();
#if UseGC
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
#endif
Debug.WriteLine(ctid + " - OnTileLoadComplete: " + lastTileLoadTimeMs + "ms, MemoryCacheSize: " + GMaps.Instance.MemoryCache.Size + "MB");
 
if (OnTileLoadComplete != null)
{
OnTileLoadComplete(lastTileLoadTimeMs);
}
}
 
public AutoResetEvent Refresh = new AutoResetEvent(false);
 
public bool updatingBounds = false;
 
/// <summary>
/// updates map bounds
/// </summary>
void UpdateBounds()
{
if (!IsStarted || Provider.Equals(EmptyProvider.Instance))
{
return;
}
 
updatingBounds = true;
 
tileDrawingListLock.AcquireWriterLock();
try
{
#region -- find tiles around --
tileDrawingList.Clear();
 
for (long i = (int)Math.Floor(-sizeOfMapArea.Width * scaleX), countI = (int)Math.Ceiling(sizeOfMapArea.Width * scaleX); i <= countI; i++)
{
for (long j = (int)Math.Floor(-sizeOfMapArea.Height * scaleY), countJ = (int)Math.Ceiling(sizeOfMapArea.Height * scaleY); j <= countJ; j++)
{
GPoint p = centerTileXYLocation;
p.X += i;
p.Y += j;
 
#if ContinuesMap
// ----------------------------
if(p.X < minOfTiles.Width)
{
p.X += (maxOfTiles.Width + 1);
}
 
if(p.X > maxOfTiles.Width)
{
p.X -= (maxOfTiles.Width + 1);
}
// ----------------------------
#endif
 
if (p.X >= minOfTiles.Width && p.Y >= minOfTiles.Height && p.X <= maxOfTiles.Width && p.Y <= maxOfTiles.Height)
{
DrawTile dt = new DrawTile()
{
PosXY = p,
PosPixel = new GPoint(p.X * tileRect.Width, p.Y * tileRect.Height),
DistanceSqr = (centerTileXYLocation.X - p.X) * (centerTileXYLocation.X - p.X) + (centerTileXYLocation.Y - p.Y) * (centerTileXYLocation.Y - p.Y)
};
 
if (!tileDrawingList.Contains(dt))
{
tileDrawingList.Add(dt);
}
}
}
}
 
if (GMaps.Instance.ShuffleTilesOnLoad)
{
Stuff.Shuffle<DrawTile>(tileDrawingList);
}
else
{
tileDrawingList.Sort();
}
#endregion
}
finally
{
tileDrawingListLock.ReleaseWriterLock();
}
 
#if NET40
Interlocked.Exchange(ref loadWaitCount, 0);
#else
Monitor.Enter(tileLoadQueue);
try
{
#endif
tileDrawingListLock.AcquireReaderLock();
try
{
foreach (DrawTile p in tileDrawingList)
{
LoadTask task = new LoadTask(p.PosXY, Zoom, this);
#if NET40
AddLoadTask(task);
#else
{
if (!tileLoadQueue.Contains(task))
{
tileLoadQueue.Push(task);
}
}
#endif
}
}
finally
{
tileDrawingListLock.ReleaseReaderLock();
}
 
#if !NET40
#region -- starts loader threads if needed --
 
lock (GThreadPool)
{
while (GThreadPool.Count < GThreadPoolSize)
{
Thread t = new Thread(new ThreadStart(tileLoadThread));
{
t.Name = "TileLoader: " + GThreadPool.Count;
t.IsBackground = true;
t.Priority = ThreadPriority.BelowNormal;
}
GThreadPool.Add(t);
 
Debug.WriteLine("add " + t.Name + " to GThreadPool");
 
t.Start();
}
}
#endregion
#endif
{
LastTileLoadStart = DateTime.Now;
Debug.WriteLine("OnTileLoadStart - at zoom " + Zoom + ", time: " + LastTileLoadStart.TimeOfDay);
}
#if !NET40
loadWaitCount = 0;
Monitor.PulseAll(tileLoadQueue);
}
finally
{
Monitor.Exit(tileLoadQueue);
}
#endif
updatingBounds = false;
 
if (OnTileLoadStart != null)
{
OnTileLoadStart();
}
}
 
/// <summary>
/// updates ground resolution info
/// </summary>
void UpdateGroundResolution()
{
double rez = Provider.Projection.GetGroundResolution(Zoom, Position.Lat);
pxRes100m = (int)(100.0 / rez); // 100 meters
pxRes1000m = (int)(1000.0 / rez); // 1km
pxRes10km = (int)(10000.0 / rez); // 10km
pxRes100km = (int)(100000.0 / rez); // 100km
pxRes1000km = (int)(1000000.0 / rez); // 1000km
pxRes5000km = (int)(5000000.0 / rez); // 5000km
}
 
#region IDisposable Members
 
~Core()
{
Dispose(false);
}
 
void Dispose(bool disposing)
{
if (IsStarted)
{
if (invalidator != null)
{
invalidator.CancelAsync();
invalidator.DoWork -= new DoWorkEventHandler(invalidatorWatch);
invalidator.Dispose();
invalidator = null;
}
 
if (Refresh != null)
{
Refresh.Set();
Refresh.Close();
Refresh = null;
}
 
int x = Interlocked.Decrement(ref instances);
Debug.WriteLine("OnMapClose: " + x);
 
CancelAsyncTasks();
IsStarted = false;
 
if (Matrix != null)
{
Matrix.Dispose();
Matrix = null;
}
 
if (FailedLoads != null)
{
lock (FailedLoads)
{
FailedLoads.Clear();
RaiseEmptyTileError = false;
}
FailedLoads = null;
}
 
tileDrawingListLock.AcquireWriterLock();
try
{
tileDrawingList.Clear();
}
finally
{
tileDrawingListLock.ReleaseWriterLock();
}
 
#if NET40
//TODO: maybe
#else
// cancel waiting loaders
Monitor.Enter(tileLoadQueue);
try
{
Monitor.PulseAll(tileLoadQueue);
}
finally
{
Monitor.Exit(tileLoadQueue);
}
 
lock (GThreadPool)
{
#if PocketPC
Debug.WriteLine("waiting until loaders are stopped...");
while(GThreadPool.Count > 0)
{
var t = GThreadPool[0];
 
if (t.State != ThreadState.Stopped)
{
var tr = t.Join(1111);
 
Debug.WriteLine(t.Name + ", " + t.State);
 
if (!tr)
{
continue;
}
else
{
GThreadPool.Remove(t);
}
}
else
{
GThreadPool.Remove(t);
}
}
Thread.Sleep(1111);
#endif
}
#endif
 
if (tileDrawingListLock != null)
{
tileDrawingListLock.Dispose();
tileDrawingListLock = null;
tileDrawingList = null;
}
 
if (x == 0)
{
#if DEBUG
GMaps.Instance.CancelTileCaching();
#endif
GMaps.Instance.noMapInstances = true;
GMaps.Instance.WaitForCache.Set();
if (disposing)
{
GMaps.Instance.MemoryCache.Clear();
}
}
}
}
 
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
 
#endregion
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/DrawTile.cs
0,0 → 1,37

using System;
namespace GMap.NET.Internals
{
/// <summary>
/// struct for drawing tile
/// </summary>
internal struct DrawTile : IEquatable<DrawTile>, IComparable<DrawTile>
{
public GPoint PosXY;
public GPoint PosPixel;
public double DistanceSqr;
 
public override string ToString()
{
return PosXY + ", px: " + PosPixel;
}
 
#region IEquatable<DrawTile> Members
 
public bool Equals(DrawTile other)
{
return (PosXY == other.PosXY);
}
 
#endregion
 
#region IComparable<DrawTile> Members
 
public int CompareTo(DrawTile other)
{
return other.DistanceSqr.CompareTo(DistanceSqr);
}
 
#endregion
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/FastReaderWriterLock.cs
0,0 → 1,194
#if !MONO && !PocketPC
#define UseFastResourceLock
#endif
 
namespace GMap.NET.Internals
{
using System;
using System.Threading;
#if !MONO
using System.Runtime.InteropServices;
#endif
 
/// <summary>
/// custom ReaderWriterLock
/// in Vista and later uses integrated Slim Reader/Writer (SRW) Lock
/// http://msdn.microsoft.com/en-us/library/aa904937(VS.85).aspx
/// http://msdn.microsoft.com/en-us/magazine/cc163405.aspx#S2
/// </summary>
public sealed class FastReaderWriterLock : IDisposable
{
#if !MONO && !PocketPC
private static class NativeMethods
{
// Methods
[DllImport("Kernel32", ExactSpelling = true)]
internal static extern void AcquireSRWLockExclusive(ref IntPtr srw);
[DllImport("Kernel32", ExactSpelling = true)]
internal static extern void AcquireSRWLockShared(ref IntPtr srw);
[DllImport("Kernel32", ExactSpelling = true)]
internal static extern void InitializeSRWLock(out IntPtr srw);
[DllImport("Kernel32", ExactSpelling = true)]
internal static extern void ReleaseSRWLockExclusive(ref IntPtr srw);
[DllImport("Kernel32", ExactSpelling = true)]
internal static extern void ReleaseSRWLockShared(ref IntPtr srw);
}
 
IntPtr LockSRW = IntPtr.Zero;
 
public FastReaderWriterLock()
{
if (UseNativeSRWLock)
{
NativeMethods.InitializeSRWLock(out this.LockSRW);
}
else
{
#if UseFastResourceLock
pLock = new FastResourceLock();
#endif
}
}
 
#if UseFastResourceLock
~FastReaderWriterLock()
{
Dispose(false);
}
 
void Dispose(bool disposing)
{
if (pLock != null)
{
pLock.Dispose();
pLock = null;
}
}
 
FastResourceLock pLock;
#endif
 
static readonly bool UseNativeSRWLock = Stuff.IsRunningOnVistaOrLater() && IntPtr.Size == 4; // works only in 32-bit mode, any ideas on native 64-bit support?
 
#endif
 
#if !UseFastResourceLock
Int32 busy = 0;
Int32 readCount = 0;
#endif
 
public void AcquireReaderLock()
{
#if !MONO && !PocketPC
if (UseNativeSRWLock)
{
NativeMethods.AcquireSRWLockShared(ref LockSRW);
}
else
#endif
{
#if UseFastResourceLock
pLock.AcquireShared();
#else
Thread.BeginCriticalRegion();
 
while(Interlocked.CompareExchange(ref busy, 1, 0) != 0)
{
Thread.Sleep(1);
}
 
Interlocked.Increment(ref readCount);
 
// somehow this fix deadlock on heavy reads
Thread.Sleep(0);
Thread.Sleep(0);
Thread.Sleep(0);
Thread.Sleep(0);
Thread.Sleep(0);
Thread.Sleep(0);
Thread.Sleep(0);
 
Interlocked.Exchange(ref busy, 0);
#endif
}
}
 
public void ReleaseReaderLock()
{
#if !MONO && !PocketPC
if (UseNativeSRWLock)
{
NativeMethods.ReleaseSRWLockShared(ref LockSRW);
}
else
#endif
{
#if UseFastResourceLock
pLock.ReleaseShared();
#else
Interlocked.Decrement(ref readCount);
Thread.EndCriticalRegion();
#endif
}
}
 
public void AcquireWriterLock()
{
#if !MONO && !PocketPC
if (UseNativeSRWLock)
{
NativeMethods.AcquireSRWLockExclusive(ref LockSRW);
}
else
#endif
{
#if UseFastResourceLock
pLock.AcquireExclusive();
#else
Thread.BeginCriticalRegion();
 
while(Interlocked.CompareExchange(ref busy, 1, 0) != 0)
{
Thread.Sleep(1);
}
 
while(Interlocked.CompareExchange(ref readCount, 0, 0) != 0)
{
Thread.Sleep(1);
}
#endif
}
}
 
public void ReleaseWriterLock()
{
#if !MONO && !PocketPC
if (UseNativeSRWLock)
{
NativeMethods.ReleaseSRWLockExclusive(ref LockSRW);
}
else
#endif
{
#if UseFastResourceLock
pLock.ReleaseExclusive();
#else
Interlocked.Exchange(ref busy, 0);
Thread.EndCriticalRegion();
#endif
}
}
 
#region IDisposable Members
 
public void Dispose()
{
#if UseFastResourceLock
this.Dispose(true);
GC.SuppressFinalize(this);
#endif
}
 
#endregion
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/FastResourceLock.cs
0,0 → 1,976
/*
* Process Hacker -
* fast resource lock
*
* Copyright (C) 2009 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
 
//#define DEFER_EVENT_CREATION
//#define ENABLE_STATISTICS
//#define RIGOROUS_CHECKS
 
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading;
 
namespace GMap.NET.Internals
{
#if !MONO && !PocketPC
/// <summary>
/// Provides a fast resource (reader-writer) lock.
/// </summary>
/// <remarks>
/// There are three types of acquire methods in this lock:
///
/// Normal methods (AcquireExclusive, AcquireShared) are preferred
/// for general purpose use.
/// Busy wait methods (SpinAcquireExclusive, SpinAcquireShared) are
/// preferred if very little time is spent while the lock is acquired.
/// However, these do not give exclusive acquires precedence over
/// shared acquires.
/// Try methods (TryAcquireExclusive, TryAcquireShared) can be used to
/// quickly test if the lock is available.
///
/// Note that all three types of functions can be used concurrently
/// in the same class instance.
/// </remarks>
internal sealed class FastResourceLock : IDisposable
{
// Details
//
// Resource lock value width: 32 bits.
// Lock owned (either exclusive or shared): L (1 bit).
// Exclusive waking: W (1 bit).
// Shared owners count: SC (10 bits).
// Shared waiters count: SW (10 bits).
// Exclusive waiters count: EW (10 bits).
//
// Acquire exclusive:
// {L=0,W=0,SC=0,SW,EW=0} -> {L=1,W=0,SC=0,SW,EW=0}
// {L=0,W=1,SC=0,SW,EW} or {L=1,W,SC,SW,EW} ->
// {L,W,SC,SW,EW+1},
// wait on event,
// {L=0,W=1,SC=0,SW,EW} -> {L=1,W=0,SC=0,SW,EW}
//
// Acquire shared:
// {L=0,W=0,SC=0,SW,EW=0} -> {L=1,W=0,SC=1,SW,EW=0}
// {L=1,W=0,SC>0,SW,EW=0} -> {L=1,W=0,SC+1,SW,EW=0}
// {L=1,W=0,SC=0,SW,EW=0} or {L,W=1,SC,SW,EW} or
// {L,W,SC,SW,EW>0} -> {L,W,SC,SW+1,EW},
// wait on event,
// retry.
//
// Release exclusive:
// {L=1,W=0,SC=0,SW,EW>0} ->
// {L=0,W=1,SC=0,SW,EW-1},
// release one exclusive waiter.
// {L=1,W=0,SC=0,SW,EW=0} ->
// {L=0,W=0,SC=0,SW=0,EW=0},
// release all shared waiters.
//
// Note that we never do a direct acquire when W=1
// (i.e. L=0 if W=1), so here we don't have to check
// the value of W.
//
// Release shared:
// {L=1,W=0,SC>1,SW,EW} -> {L=1,W=0,SC-1,SW,EW}
// {L=1,W=0,SC=1,SW,EW=0} -> {L=0,W=0,SC=0,SW,EW=0}
// {L=1,W=0,SC=1,SW,EW>0} ->
// {L=0,W=1,SC=0,SW,EW-1},
// release one exclusive waiter.
//
// Again, we don't need to check the value of W.
//
// Convert exclusive to shared:
// {L=1,W=0,SC=0,SW,EW} ->
// {L=1,W=0,SC=1,SW=0,EW},
// release all shared waiters.
//
// Convert shared to exclusive:
// {L=1,W=0,SC=1,SW,EW} ->
// {L=1,W=0,SC=0,SW,EW}
//
 
/* */
 
// Note: I have included many small optimizations in the code
// because of the CLR's dumbass JIT compiler.
 
#region Constants
 
// Lock owned: 1 bit.
private const int LockOwned = 0x1;
 
// Exclusive waking: 1 bit.
private const int LockExclusiveWaking = 0x2;
 
// Shared owners count: 10 bits.
private const int LockSharedOwnersShift = 2;
private const int LockSharedOwnersMask = 0x3ff;
private const int LockSharedOwnersIncrement = 0x4;
 
// Shared waiters count: 10 bits.
private const int LockSharedWaitersShift = 12;
private const int LockSharedWaitersMask = 0x3ff;
private const int LockSharedWaitersIncrement = 0x1000;
 
// Exclusive waiters count: 10 bits.
private const int LockExclusiveWaitersShift = 22;
private const int LockExclusiveWaitersMask = 0x3ff;
private const int LockExclusiveWaitersIncrement = 0x400000;
 
private const int ExclusiveMask = LockExclusiveWaking | (LockExclusiveWaitersMask << LockExclusiveWaitersShift);
 
#endregion
 
public struct Statistics
{
/// <summary>
/// The number of times the lock has been acquired in exclusive mode.
/// </summary>
public int AcqExcl;
/// <summary>
/// The number of times the lock has been acquired in shared mode.
/// </summary>
public int AcqShrd;
/// <summary>
/// The number of times either the fast path was retried due to the
/// spin count or the exclusive waiter went to sleep.
/// </summary>
/// <remarks>
/// This number is usually much higher than AcqExcl, and indicates
/// a good spin count if AcqExclSlp is very small.
/// </remarks>
public int AcqExclCont;
/// <summary>
/// The number of times either the fast path was retried due to the
/// spin count or the shared waiter went to sleep.
/// </summary>
/// <remarks>
/// This number is usually much higher than AcqShrd, and indicates
/// a good spin count if AcqShrdSlp is very small.
/// </remarks>
public int AcqShrdCont;
/// <summary>
/// The number of times exclusive waiters have gone to sleep.
/// </summary>
/// <remarks>
/// If this number is high and not much time is spent in the
/// lock, consider increasing the spin count.
/// </remarks>
public int AcqExclSlp;
/// <summary>
/// The number of times shared waiters have gone to sleep.
/// </summary>
/// <remarks>
/// If this number is high and not much time is spent in the
/// lock, consider increasing the spin count.
/// </remarks>
public int AcqShrdSlp;
/// <summary>
/// The highest number of exclusive waiters at any one time.
/// </summary>
public int PeakExclWtrsCount;
/// <summary>
/// The highest number of shared waiters at any one time.
/// </summary>
public int PeakShrdWtrsCount;
}
 
// The number of times to spin before going to sleep.
private static readonly int SpinCount = NativeMethods.SpinCount;
 
private int _value;
private IntPtr _sharedWakeEvent;
private IntPtr _exclusiveWakeEvent;
 
#if ENABLE_STATISTICS
private int _acqExclCount = 0;
private int _acqShrdCount = 0;
private int _acqExclContCount = 0;
private int _acqShrdContCount = 0;
private int _acqExclSlpCount = 0;
private int _acqShrdSlpCount = 0;
private int _peakExclWtrsCount = 0;
private int _peakShrdWtrsCount = 0;
#endif
 
/// <summary>
/// Creates a FastResourceLock.
/// </summary>
public FastResourceLock()
{
_value = 0;
 
#if !DEFER_EVENT_CREATION
_sharedWakeEvent = NativeMethods.CreateSemaphore(IntPtr.Zero, 0, int.MaxValue, null);
_exclusiveWakeEvent = NativeMethods.CreateSemaphore(IntPtr.Zero, 0, int.MaxValue, null);
#endif
}
 
~FastResourceLock()
{
this.Dispose(false);
}
 
private void Dispose(bool disposing)
{
if(_sharedWakeEvent != IntPtr.Zero)
{
NativeMethods.CloseHandle(_sharedWakeEvent);
_sharedWakeEvent = IntPtr.Zero;
}
 
if(_exclusiveWakeEvent != IntPtr.Zero)
{
NativeMethods.CloseHandle(_exclusiveWakeEvent);
_exclusiveWakeEvent = IntPtr.Zero;
}
}
 
/// <summary>
/// Disposes resources associated with the FastResourceLock.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
 
/// <summary>
/// Gets the number of exclusive waiters.
/// </summary>
public int ExclusiveWaiters
{
get
{
return (_value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask;
}
}
 
/// <summary>
/// Gets whether the lock is owned in either
/// exclusive or shared mode.
/// </summary>
public bool Owned
{
get
{
return (_value & LockOwned) != 0;
}
}
 
/// <summary>
/// Gets the number of shared owners.
/// </summary>
public int SharedOwners
{
get
{
return (_value >> LockSharedOwnersShift) & LockSharedOwnersMask;
}
}
 
/// <summary>
/// Gets the number of shared waiters.
/// </summary>
public int SharedWaiters
{
get
{
return (_value >> LockSharedWaitersShift) & LockSharedWaitersMask;
}
}
 
/// <summary>
/// Acquires the lock in exclusive mode, blocking
/// if necessary.
/// </summary>
/// <remarks>
/// Exclusive acquires are given precedence over shared
/// acquires.
/// </remarks>
public void AcquireExclusive()
{
int value;
int i = 0;
 
#if ENABLE_STATISTICS
Interlocked.Increment(ref _acqExclCount);
 
#endif
while(true)
{
value = _value;
 
// Case 1: lock not owned AND an exclusive waiter is not waking up.
// Here we don't have to check if there are exclusive waiters, because
// if there are the lock would be owned, and we are checking that anyway.
if((value & (LockOwned | LockExclusiveWaking)) == 0)
{
#if RIGOROUS_CHECKS
System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 0);
System.Diagnostics.Trace.Assert(((value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask) == 0);
 
#endif
if(Interlocked.CompareExchange(
ref _value,
value + LockOwned,
value
) == value)
break;
}
// Case 2: lock owned OR lock not owned and an exclusive waiter is waking up.
// The second case means an exclusive waiter has just been woken up and is
// going to acquire the lock. We have to go to sleep to make sure we don't
// steal the lock.
else if(i >= SpinCount)
{
#if DEFER_EVENT_CREATION
// This call must go *before* the next operation. Otherwise,
// we will have a race condition between potential releasers
// and us.
this.EnsureEventCreated(ref _exclusiveWakeEvent);
 
#endif
if(Interlocked.CompareExchange(
ref _value,
value + LockExclusiveWaitersIncrement,
value
) == value)
{
#if ENABLE_STATISTICS
Interlocked.Increment(ref _acqExclSlpCount);
 
int exclWtrsCount = (value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask;
 
Interlocked2.Set(
ref _peakExclWtrsCount,
(p) => p < exclWtrsCount,
(p) => exclWtrsCount
);
 
#endif
// Go to sleep.
if(NativeMethods.WaitForSingleObject(
_exclusiveWakeEvent,
Timeout.Infinite
) != NativeMethods.WaitObject0)
UtilsBreak("Utils.MsgFailedToWaitIndefinitely");
 
// Acquire the lock.
// At this point *no one* should be able to steal the lock from us.
do
{
value = _value;
#if RIGOROUS_CHECKS
 
System.Diagnostics.Trace.Assert((value & LockOwned) == 0);
System.Diagnostics.Trace.Assert((value & LockExclusiveWaking) != 0);
#endif
} while(Interlocked.CompareExchange(
ref _value,
value + LockOwned - LockExclusiveWaking,
value
) != value);
 
break;
}
}
 
#if ENABLE_STATISTICS
Interlocked.Increment(ref _acqExclContCount);
#endif
i++;
}
}
 
/// <summary>
/// Acquires the lock in shared mode, blocking
/// if necessary.
/// </summary>
/// <remarks>
/// Exclusive acquires are given precedence over shared
/// acquires.
/// </remarks>
public void AcquireShared()
{
int value;
int i = 0;
 
#if ENABLE_STATISTICS
Interlocked.Increment(ref _acqShrdCount);
 
#endif
while(true)
{
value = _value;
 
// Case 1: lock not owned AND no exclusive waiter is waking up AND
// there are no shared owners AND there are no exclusive waiters
if((value & (
LockOwned |
(LockSharedOwnersMask << LockSharedOwnersShift) |
ExclusiveMask
)) == 0)
{
if(Interlocked.CompareExchange(
ref _value,
value + LockOwned + LockSharedOwnersIncrement,
value
) == value)
break;
}
// Case 2: lock is owned AND no exclusive waiter is waking up AND
// there are shared owners AND there are no exclusive waiters
else if(
(value & LockOwned) != 0 &&
((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0 &&
(value & ExclusiveMask) == 0
)
{
if(Interlocked.CompareExchange(
ref _value,
value + LockSharedOwnersIncrement,
value
) == value)
break;
}
// Other cases.
else if(i >= SpinCount)
{
#if DEFER_EVENT_CREATION
this.EnsureEventCreated(ref _sharedWakeEvent);
 
#endif
if(Interlocked.CompareExchange(
ref _value,
value + LockSharedWaitersIncrement,
value
) == value)
{
#if ENABLE_STATISTICS
Interlocked.Increment(ref _acqShrdSlpCount);
 
int shrdWtrsCount = (value >> LockSharedWaitersShift) & LockSharedWaitersMask;
 
Interlocked2.Set(
ref _peakShrdWtrsCount,
(p) => p < shrdWtrsCount,
(p) => shrdWtrsCount
);
 
#endif
// Go to sleep.
if(NativeMethods.WaitForSingleObject(
_sharedWakeEvent,
Timeout.Infinite
) != NativeMethods.WaitObject0)
UtilsBreak("Utils.MsgFailedToWaitIndefinitely");
 
// Go back and try again.
continue;
}
}
 
#if ENABLE_STATISTICS
Interlocked.Increment(ref _acqShrdContCount);
#endif
i++;
}
}
 
public static void UtilsBreak(string logMessage)
{
System.Diagnostics.Debugger.Log(0, "Error", logMessage);
System.Diagnostics.Debugger.Break();
}
 
/// <summary>
/// Converts the ownership mode from exclusive to shared.
/// </summary>
/// <remarks>
/// Exclusive acquires are not given a chance to acquire
/// the lock before this function does - as a result,
/// this function will never block.
/// </remarks>
public void ConvertExclusiveToShared()
{
int value;
int sharedWaiters;
 
while(true)
{
value = _value;
#if RIGOROUS_CHECKS
 
System.Diagnostics.Trace.Assert((value & LockOwned) != 0);
System.Diagnostics.Trace.Assert((value & LockExclusiveWaking) == 0);
System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 0);
#endif
 
sharedWaiters = (value >> LockSharedWaitersShift) & LockSharedWaitersMask;
 
if(Interlocked.CompareExchange(
ref _value,
(value + LockSharedOwnersIncrement) & ~(LockSharedWaitersMask << LockSharedWaitersShift),
value
) == value)
{
if(sharedWaiters != 0)
NativeMethods.ReleaseSemaphore(_sharedWakeEvent, sharedWaiters, IntPtr.Zero);
 
break;
}
}
}
 
#if DEFER_EVENT_CREATION
/// <summary>
/// Checks if the specified event has been created, and
/// if not, creates it.
/// </summary>
/// <param name="handle">A reference to the event handle.</param>
private void EnsureEventCreated(ref IntPtr handle)
{
IntPtr eventHandle;
 
if(Thread.VolatileRead(ref handle) != IntPtr.Zero)
return;
 
eventHandle = NativeMethods.CreateSemaphore(IntPtr.Zero, 0, int.MaxValue, null);
 
if(Interlocked.CompareExchange(ref handle, eventHandle, IntPtr.Zero) != IntPtr.Zero)
NativeMethods.CloseHandle(eventHandle);
}
#endif
 
/// <summary>
/// Gets statistics information for the lock.
/// </summary>
/// <returns>A structure containing statistics.</returns>
public Statistics GetStatistics()
{
#if ENABLE_STATISTICS
return new Statistics()
{
AcqExcl = _acqExclCount,
AcqShrd = _acqShrdCount,
AcqExclCont = _acqExclContCount,
AcqShrdCont = _acqShrdContCount,
AcqExclSlp = _acqExclSlpCount,
AcqShrdSlp = _acqShrdSlpCount,
PeakExclWtrsCount = _peakExclWtrsCount,
PeakShrdWtrsCount = _peakShrdWtrsCount
};
#else
return new Statistics();
#endif
}
 
/// <summary>
/// Releases the lock in exclusive mode.
/// </summary>
public void ReleaseExclusive()
{
int value;
 
while(true)
{
value = _value;
#if RIGOROUS_CHECKS
 
System.Diagnostics.Trace.Assert((value & LockOwned) != 0);
System.Diagnostics.Trace.Assert((value & LockExclusiveWaking) == 0);
System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 0);
#endif
 
// Case 1: if we have exclusive waiters, release one.
if(((value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask) != 0)
{
if(Interlocked.CompareExchange(
ref _value,
value - LockOwned + LockExclusiveWaking - LockExclusiveWaitersIncrement,
value
) == value)
{
NativeMethods.ReleaseSemaphore(_exclusiveWakeEvent, 1, IntPtr.Zero);
 
break;
}
}
// Case 2: if we have shared waiters, release all of them.
else
{
int sharedWaiters;
 
sharedWaiters = (value >> LockSharedWaitersShift) & LockSharedWaitersMask;
 
if(Interlocked.CompareExchange(
ref _value,
value & ~(LockOwned | (LockSharedWaitersMask << LockSharedWaitersShift)),
value
) == value)
{
if(sharedWaiters != 0)
NativeMethods.ReleaseSemaphore(_sharedWakeEvent, sharedWaiters, IntPtr.Zero);
 
break;
}
}
}
}
 
/// <summary>
/// Releases the lock in shared mode.
/// </summary>
public void ReleaseShared()
{
int value;
int sharedOwners;
 
while(true)
{
value = _value;
#if RIGOROUS_CHECKS
 
System.Diagnostics.Trace.Assert((value & LockOwned) != 0);
System.Diagnostics.Trace.Assert((value & LockExclusiveWaking) == 0);
System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0);
#endif
 
sharedOwners = (value >> LockSharedOwnersShift) & LockSharedOwnersMask;
 
// Case 1: there are multiple shared owners.
if(sharedOwners > 1)
{
if(Interlocked.CompareExchange(
ref _value,
value - LockSharedOwnersIncrement,
value
) == value)
break;
}
// Case 2: we are the last shared owner AND there are exclusive waiters.
else if(((value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask) != 0)
{
if(Interlocked.CompareExchange(
ref _value,
value - LockOwned + LockExclusiveWaking - LockSharedOwnersIncrement - LockExclusiveWaitersIncrement,
value
) == value)
{
NativeMethods.ReleaseSemaphore(_exclusiveWakeEvent, 1, IntPtr.Zero);
 
break;
}
}
// Case 3: we are the last shared owner AND there are no exclusive waiters.
else
{
if(Interlocked.CompareExchange(
ref _value,
value - LockOwned - LockSharedOwnersIncrement,
value
) == value)
break;
}
}
}
 
/// <summary>
/// Acquires the lock in exclusive mode, busy waiting
/// if necessary.
/// </summary>
/// <remarks>
/// Exclusive acquires are *not* given precedence over shared
/// acquires for busy wait methods.
/// </remarks>
public void SpinAcquireExclusive()
{
int value;
 
while(true)
{
value = _value;
 
if((value & (LockOwned | LockExclusiveWaking)) == 0)
{
if(Interlocked.CompareExchange(
ref _value,
value + LockOwned,
value
) == value)
break;
}
 
if(NativeMethods.SpinEnabled)
Thread.SpinWait(8);
else
Thread.Sleep(0);
}
}
 
/// <summary>
/// Acquires the lock in shared mode, busy waiting
/// if necessary.
/// </summary>
/// <remarks>
/// Exclusive acquires are *not* given precedence over shared
/// acquires for busy wait methods.
/// </remarks>
public void SpinAcquireShared()
{
int value;
 
while(true)
{
value = _value;
 
if((value & ExclusiveMask) == 0)
{
if((value & LockOwned) == 0)
{
if(Interlocked.CompareExchange(
ref _value,
value + LockOwned + LockSharedOwnersIncrement,
value
) == value)
break;
}
else if(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0)
{
if(Interlocked.CompareExchange(
ref _value,
value + LockSharedOwnersIncrement,
value
) == value)
break;
}
}
 
if(NativeMethods.SpinEnabled)
Thread.SpinWait(8);
else
Thread.Sleep(0);
}
}
 
/// <summary>
/// Converts the ownership mode from shared to exclusive,
/// busy waiting if necessary.
/// </summary>
public void SpinConvertSharedToExclusive()
{
int value;
 
while(true)
{
value = _value;
 
// Can't convert if there are other shared owners.
if(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 1)
{
if(Interlocked.CompareExchange(
ref _value,
value - LockSharedOwnersIncrement,
value
) == value)
break;
}
 
if(NativeMethods.SpinEnabled)
Thread.SpinWait(8);
else
Thread.Sleep(0);
}
}
 
/// <summary>
/// Attempts to acquire the lock in exclusive mode.
/// </summary>
/// <returns>Whether the lock was acquired.</returns>
public bool TryAcquireExclusive()
{
int value;
 
value = _value;
 
if((value & (LockOwned | LockExclusiveWaking)) != 0)
return false;
 
return Interlocked.CompareExchange(
ref _value,
value + LockOwned,
value
) == value;
}
 
/// <summary>
/// Attempts to acquire the lock in shared mode.
/// </summary>
/// <returns>Whether the lock was acquired.</returns>
public bool TryAcquireShared()
{
int value;
 
value = _value;
 
if((value & ExclusiveMask) != 0)
return false;
 
if((value & LockOwned) == 0)
{
return Interlocked.CompareExchange(
ref _value,
value + LockOwned + LockSharedOwnersIncrement,
value
) == value;
}
else if(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0)
{
return Interlocked.CompareExchange(
ref _value,
value + LockSharedOwnersIncrement,
value
) == value;
}
else
{
return false;
}
}
 
/// <summary>
/// Attempts to convert the ownership mode from shared
/// to exclusive.
/// </summary>
/// <returns>Whether the lock was converted.</returns>
public bool TryConvertSharedToExclusive()
{
int value;
 
while(true)
{
value = _value;
#if RIGOROUS_CHECKS
 
System.Diagnostics.Trace.Assert((value & LockOwned) != 0);
System.Diagnostics.Trace.Assert((value & LockExclusiveWaking) == 0);
System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0);
#endif
 
// Can't convert if there are other shared owners.
if(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 1)
return false;
 
if(Interlocked.CompareExchange(
ref _value,
value - LockSharedOwnersIncrement,
value
) == value)
return true;
}
}
}
 
[SuppressUnmanagedCodeSecurity]
internal class NativeMethods
{
public const int WaitObject0 = 0x0;
public const int WaitAbandoned = 0x80;
public const int WaitTimeout = 0x102;
public const int WaitFailed = -1;
 
public static readonly int SpinCount = Environment.ProcessorCount != 1 ? 4000 : 0;
public static readonly bool SpinEnabled = Environment.ProcessorCount != 1;
 
// We need to import some stuff. We can't use
// ProcessHacker.Native because it depends on this library.
 
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(
[In] IntPtr Handle
);
 
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr CreateEvent(
[In] [Optional] IntPtr EventAttributes,
[In] bool ManualReset,
[In] bool InitialState,
[In] [Optional] string Name
);
 
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr CreateSemaphore(
[In] [Optional] IntPtr SemaphoreAttributes,
[In] int InitialCount,
[In] int MaximumCount,
[In] [Optional] string Name
);
 
[DllImport("kernel32.dll")]
public static extern bool ReleaseSemaphore(
[In] IntPtr SemaphoreHandle,
[In] int ReleaseCount,
[In] IntPtr PreviousCount // out int
);
 
[DllImport("kernel32.dll")]
public static extern bool ResetEvent(
[In] IntPtr EventHandle
);
 
[DllImport("kernel32.dll")]
public static extern bool SetEvent(
[In] IntPtr EventHandle
);
 
[DllImport("kernel32.dll")]
public static extern int WaitForSingleObject(
[In] IntPtr Handle,
[In] int Milliseconds
);
 
[DllImport("ntdll.dll")]
public static extern int NtCreateKeyedEvent(
[Out] out IntPtr KeyedEventHandle,
[In] int DesiredAccess,
[In] [Optional] IntPtr ObjectAttributes,
[In] int Flags
);
 
[DllImport("ntdll.dll")]
public static extern int NtReleaseKeyedEvent(
[In] IntPtr KeyedEventHandle,
[In] IntPtr KeyValue,
[In] bool Alertable,
[In] [Optional] IntPtr Timeout
);
 
[DllImport("ntdll.dll")]
public static extern int NtWaitForKeyedEvent(
[In] IntPtr KeyedEventHandle,
[In] IntPtr KeyValue,
[In] bool Alertable,
[In] [Optional] IntPtr Timeout
);
}
#endif
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/KiberTileCache.cs
0,0 → 1,91

namespace GMap.NET.Internals
{
using System.Collections.Generic;
using System.IO;
using System;
using System.Diagnostics;
 
/// <summary>
/// kiber speed memory cache for tiles with history support ;}
/// </summary>
internal class KiberTileCache : Dictionary<RawTile, byte[]>
{
public KiberTileCache() : base(new RawTileComparer())
{
}
 
readonly Queue<RawTile> Queue = new Queue<RawTile>();
 
/// <summary>
/// the amount of tiles in MB to keep in memmory, default: 22MB, if each ~100Kb it's ~222 tiles
/// </summary>
#if !PocketPC
public int MemoryCacheCapacity = 22;
#else
public int MemoryCacheCapacity = 3;
#endif
 
long memoryCacheSize = 0;
 
/// <summary>
/// current memmory cache size in MB
/// </summary>
public double MemoryCacheSize
{
get
{
return memoryCacheSize / 1048576.0;
}
}
 
public new void Add(RawTile key, byte[] value)
{
Queue.Enqueue(key);
base.Add(key, value);
 
memoryCacheSize += value.Length;
}
 
// do not allow directly removal of elements
private new void Remove(RawTile key)
{
 
}
 
public new void Clear()
{
Queue.Clear();
base.Clear();
memoryCacheSize = 0;
}
 
internal void RemoveMemoryOverload()
{
while(MemoryCacheSize > MemoryCacheCapacity)
{
if(Keys.Count > 0 && Queue.Count > 0)
{
RawTile first = Queue.Dequeue();
try
{
var m = base[first];
{
base.Remove(first);
memoryCacheSize -= m.Length;
}
m = null;
}
catch(Exception ex)
{
Debug.WriteLine("RemoveMemoryOverload: " + ex);
}
}
else
{
break;
}
}
}
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/LoadTask.cs
0,0 → 1,50

using System;
using System.Collections.Generic;
namespace GMap.NET.Internals
{
/// <summary>
/// tile load task
/// </summary>
internal struct LoadTask : IEquatable<LoadTask>
{
public GPoint Pos;
public int Zoom;
 
internal Core Core;
 
public LoadTask(GPoint pos, int zoom, Core core = null)
{
Pos = pos;
Zoom = zoom;
Core = core;
}
 
public override string ToString()
{
return Zoom + " - " + Pos.ToString();
}
 
#region IEquatable<LoadTask> Members
 
public bool Equals(LoadTask other)
{
return (Zoom == other.Zoom && Pos == other.Pos);
}
 
#endregion
}
 
internal class LoadTaskComparer : IEqualityComparer<LoadTask>
{
public bool Equals(LoadTask x, LoadTask y)
{
return x.Zoom == y.Zoom && x.Pos == y.Pos;
}
 
public int GetHashCode(LoadTask obj)
{
return obj.Zoom ^ obj.Pos.GetHashCode();
}
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/PureImage.cs
0,0 → 1,52

namespace GMap.NET
{
using System;
using System.IO;
 
/// <summary>
/// image abstraction proxy
/// </summary>
public abstract class PureImageProxy
{
abstract public PureImage FromStream(Stream stream);
abstract public bool Save(Stream stream, PureImage image);
 
public PureImage FromArray(byte[] data)
{
MemoryStream m = new MemoryStream(data, 0, data.Length, false, true);
var pi = FromStream(m);
if(pi != null)
{
m.Position = 0;
pi.Data = m;
}
else
{
m.Dispose();
}
m = null;
 
return pi;
}
}
 
/// <summary>
/// image abstraction
/// </summary>
public abstract class PureImage : IDisposable
{
public MemoryStream Data;
 
internal bool IsParent;
internal long Ix;
internal long Xoff;
internal long Yoff;
 
#region IDisposable Members
 
public abstract void Dispose();
 
#endregion
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/RawTile.cs
0,0 → 1,42
namespace GMap.NET.Internals
{
using System.IO;
using System;
using System.Collections.Generic;
 
/// <summary>
/// struct for raw tile
/// </summary>
internal struct RawTile
{
public int Type;
public GPoint Pos;
public int Zoom;
 
public RawTile(int Type, GPoint Pos, int Zoom)
{
this.Type = Type;
this.Pos = Pos;
this.Zoom = Zoom;
}
 
public override string ToString()
{
return Type + " at zoom " + Zoom + ", pos: " + Pos;
}
}
 
internal class RawTileComparer : IEqualityComparer<RawTile>
{
public bool Equals(RawTile x, RawTile y)
{
return x.Type == y.Type && x.Zoom == y.Zoom && x.Pos == y.Pos;
}
 
public int GetHashCode(RawTile obj)
{
return obj.Type ^ obj.Zoom ^ obj.Pos.GetHashCode();
}
}
}
 
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/AuthMethod.cs
0,0 → 1,113
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Net;
using System.Net.Sockets;
 
namespace Org.Mentalis.Network.ProxySocket.Authentication {
/// <summary>
/// Implements a SOCKS authentication scheme.
/// </summary>
/// <remarks>This is an abstract class; it must be inherited.</remarks>
internal abstract class AuthMethod {
/// <summary>
/// Initializes an AuthMethod instance.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
public AuthMethod(Socket server) {
Server = server;
}
/// <summary>
/// Authenticates the user.
/// </summary>
/// <exception cref="ProxyException">Authentication with the proxy server failed.</exception>
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public abstract void Authenticate();
/// <summary>
/// Authenticates the user asynchronously.
/// </summary>
/// <param name="callback">The method to call when the authentication is complete.</param>
/// <exception cref="ProxyException">Authentication with the proxy server failed.</exception>
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public abstract void BeginAuthenticate(HandShakeComplete callback);
/// <summary>
/// Gets or sets the socket connection with the proxy server.
/// </summary>
/// <value>The socket connection with the proxy server.</value>
protected Socket Server {
get {
return m_Server;
}
set {
if (value == null)
throw new ArgumentNullException();
m_Server = value;
}
}
/// <summary>
/// Gets or sets a byt array that can be used to store data.
/// </summary>
/// <value>A byte array to store data.</value>
protected byte[] Buffer {
get {
return m_Buffer;
}
set {
m_Buffer = value;
}
}
/// <summary>
/// Gets or sets the number of bytes that have been received from the remote proxy server.
/// </summary>
/// <value>An integer that holds the number of bytes that have been received from the remote proxy server.</value>
protected int Received {
get {
return m_Received;
}
set {
m_Received = value;
}
}
// private variables
/// <summary>Holds the value of the Buffer property.</summary>
private byte[] m_Buffer;
/// <summary>Holds the value of the Server property.</summary>
private Socket m_Server;
/// <summary>Holds the address of the method to call when the proxy has authenticated the client.</summary>
protected HandShakeComplete CallBack;
/// <summary>Holds the value of the Received property.</summary>
private int m_Received;
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/AuthNone.cs
0,0 → 1,60
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Net;
using System.Net.Sockets;
 
namespace Org.Mentalis.Network.ProxySocket.Authentication {
/// <summary>
/// This class implements the 'No Authentication' scheme.
/// </summary>
internal sealed class AuthNone : AuthMethod {
/// <summary>
/// Initializes an AuthNone instance.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
public AuthNone(Socket server) : base(server) {}
/// <summary>
/// Authenticates the user.
/// </summary>
public override void Authenticate() {
return; // Do Nothing
}
/// <summary>
/// Authenticates the user asynchronously.
/// </summary>
/// <param name="callback">The method to call when the authentication is complete.</param>
/// <remarks>This method immediately calls the callback method.</remarks>
public override void BeginAuthenticate(HandShakeComplete callback) {
callback(null);
}
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/AuthUserPass.cs
0,0 → 1,157
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
 
namespace Org.Mentalis.Network.ProxySocket.Authentication {
/// <summary>
/// This class implements the 'username/password authentication' scheme.
/// </summary>
internal sealed class AuthUserPass : AuthMethod {
/// <summary>
/// Initializes a new AuthUserPass instance.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
/// <param name="user">The username to use.</param>
/// <param name="pass">The password to use.</param>
/// <exception cref="ArgumentNullException"><c>user</c> -or- <c>pass</c> is null.</exception>
public AuthUserPass(Socket server, string user, string pass) : base(server) {
Username = user;
Password = pass;
}
/// <summary>
/// Creates an array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.
/// </summary>
/// <returns>An array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme.</returns>
private byte[] GetAuthenticationBytes() {
byte[] buffer = new byte[3 + Username.Length + Password.Length];
buffer[0] = 1;
buffer[1] = (byte)Username.Length;
Array.Copy(Encoding.ASCII.GetBytes(Username), 0, buffer, 2, Username.Length);
buffer[Username.Length + 2] = (byte)Password.Length;
Array.Copy(Encoding.ASCII.GetBytes(Password), 0, buffer, Username.Length + 3, Password.Length);
return buffer;
}
/// <summary>
/// Starts the authentication process.
/// </summary>
public override void Authenticate() {
Server.Send(GetAuthenticationBytes());
byte[] buffer = new byte[2];
int received = 0;
while (received != 2) {
received += Server.Receive(buffer, received, 2 - received, SocketFlags.None);
}
if (buffer[1] != 0) {
Server.Close();
throw new ProxyException("Username/password combination rejected.");
}
return;
}
/// <summary>
/// Starts the asynchronous authentication process.
/// </summary>
/// <param name="callback">The method to call when the authentication is complete.</param>
public override void BeginAuthenticate(HandShakeComplete callback) {
CallBack = callback;
Server.BeginSend(GetAuthenticationBytes(), 0, 3 + Username.Length + Password.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server);
return;
}
/// <summary>
/// Called when the authentication bytes have been sent.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnSent(IAsyncResult ar) {
try {
Server.EndSend(ar);
Buffer = new byte[2];
Server.BeginReceive(Buffer, 0, 2, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
} catch (Exception e) {
CallBack(e);
}
}
/// <summary>
/// Called when the socket received an authentication reply.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnReceive(IAsyncResult ar) {
try {
Received += Server.EndReceive(ar);
if (Received == Buffer.Length)
if (Buffer[1] == 0)
CallBack(null);
else
throw new ProxyException("Username/password combination not accepted.");
else
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
} catch (Exception e) {
CallBack(e);
}
}
/// <summary>
/// Gets or sets the username to use when authenticating with the proxy server.
/// </summary>
/// <value>The username to use when authenticating with the proxy server.</value>
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
private string Username {
get {
return m_Username;
}
set {
if (value == null)
throw new ArgumentNullException();
m_Username = value;
}
}
/// <summary>
/// Gets or sets the password to use when authenticating with the proxy server.
/// </summary>
/// <value>The password to use when authenticating with the proxy server.</value>
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
private string Password {
get {
return m_Password;
}
set {
if (value == null)
throw new ArgumentNullException();
m_Password = value;
}
}
// private variables
/// <summary>Holds the value of the Username property.</summary>
private string m_Username;
/// <summary>Holds the value of the Password property.</summary>
private string m_Password;
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/IAsyncProxyResult.cs
0,0 → 1,96
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Threading;
 
namespace Org.Mentalis.Network.ProxySocket {
/// <summary>
/// A class that implements the IAsyncResult interface. Objects from this class are returned by the BeginConnect method of the ProxySocket class.
/// </summary>
internal class IAsyncProxyResult : IAsyncResult {
/// <summary>Initializes the internal variables of this object</summary>
/// <param name="stateObject">An object that contains state information for this request.</param>
internal void Init(object stateObject) {
m_StateObject = stateObject;
m_Completed = false;
if (m_WaitHandle != null)
m_WaitHandle.Reset();
}
/// <summary>Initializes the internal variables of this object</summary>
internal void Reset() {
m_StateObject = null;
m_Completed = true;
if (m_WaitHandle != null)
m_WaitHandle.Set();
}
/// <summary>Gets a value that indicates whether the server has completed processing the call. It is illegal for the server to use any client supplied resources outside of the agreed upon sharing semantics after it sets the IsCompleted property to "true". Thus, it is safe for the client to destroy the resources after IsCompleted property returns "true".</summary>
/// <value>A boolean that indicates whether the server has completed processing the call.</value>
public bool IsCompleted {
get {
return m_Completed;
}
}
/// <summary>Gets a value that indicates whether the BeginXXXX call has been completed synchronously. If this is detected in the AsyncCallback delegate, it is probable that the thread that called BeginInvoke is the current thread.</summary>
/// <value>Returns false.</value>
public bool CompletedSynchronously {
get {
return false;
}
}
/// <summary>Gets an object that was passed as the state parameter of the BeginXXXX method call.</summary>
/// <value>The object that was passed as the state parameter of the BeginXXXX method call.</value>
public object AsyncState {
get {
return m_StateObject;
}
}
/// <summary>
/// The AsyncWaitHandle property returns the WaitHandle that can use to perform a WaitHandle.WaitOne or WaitAny or WaitAll. The object which implements IAsyncResult need not derive from the System.WaitHandle classes directly. The WaitHandle wraps its underlying synchronization primitive and should be signaled after the call is completed. This enables the client to wait for the call to complete instead polling. The Runtime supplies a number of waitable objects that mirror Win32 synchronization primitives e.g. ManualResetEvent, AutoResetEvent and Mutex.
/// WaitHandle supplies methods that support waiting for such synchronization objects to become signaled with "any" or "all" semantics i.e. WaitHandle.WaitOne, WaitAny and WaitAll. Such methods are context aware to avoid deadlocks. The AsyncWaitHandle can be allocated eagerly or on demand. It is the choice of the IAsyncResult implementer.
///</summary>
/// <value>The WaitHandle associated with this asynchronous result.</value>
public WaitHandle AsyncWaitHandle {
get {
if (m_WaitHandle == null)
m_WaitHandle = new ManualResetEvent(false);
return m_WaitHandle;
}
}
// private variables
/// <summary>Used internally to represent the state of the asynchronous request</summary>
internal bool m_Completed = true;
/// <summary>Holds the value of the StateObject property.</summary>
private object m_StateObject;
/// <summary>Holds the value of the WaitHandle property.</summary>
private ManualResetEvent m_WaitHandle;
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/ProxyException.cs
0,0 → 1,82
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
 
namespace Org.Mentalis.Network.ProxySocket {
/// <summary>
/// The exception that is thrown when a proxy error occurs.
/// </summary>
internal class ProxyException : Exception {
/// <summary>
/// Initializes a new instance of the ProxyException class.
/// </summary>
public ProxyException() : this("An error occured while talking to the proxy server.") {}
/// <summary>
/// Initializes a new instance of the ProxyException class.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public ProxyException(string message) : base(message) {}
/// <summary>
/// Initializes a new instance of the ProxyException class.
/// </summary>
/// <param name="socks5Error">The error number returned by a SOCKS5 server.</param>
public ProxyException(int socks5Error) : this(ProxyException.Socks5ToString(socks5Error)) {}
/// <summary>
/// Converts a SOCKS5 error number to a human readable string.
/// </summary>
/// <param name="socks5Error">The error number returned by a SOCKS5 server.</param>
/// <returns>A string representation of the specified SOCKS5 error number.</returns>
public static string Socks5ToString(int socks5Error) {
switch(socks5Error) {
case 0:
return "Connection succeeded.";
case 1:
return "General SOCKS server failure.";
case 2:
return "Connection not allowed by ruleset.";
case 3:
return "Network unreachable.";
case 4:
return "Host unreachable.";
case 5:
return "Connection refused.";
case 6:
return "TTL expired.";
case 7:
return "Command not supported.";
case 8:
return "Address type not supported.";
default:
return "Unspecified SOCKS error.";
}
}
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/ProxySocket.cs
0,0 → 1,467
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Net;
using System.Net.Sockets;
 
// Implements a number of classes to allow Sockets to connect trough a firewall.
namespace Org.Mentalis.Network.ProxySocket
{
/// <summary>
/// Specifies the type of proxy servers that an instance of the ProxySocket class can use.
/// </summary>
internal enum ProxyTypes
{
/// <summary>No proxy server; the ProxySocket object behaves exactly like an ordinary Socket object.</summary>
None,
/// <summary>A SOCKS4[A] proxy server.</summary>
Socks4,
/// <summary>A SOCKS5 proxy server.</summary>
Socks5
}
 
/// <summary>
/// Implements a Socket class that can connect trough a SOCKS proxy server.
/// </summary>
/// <remarks>This class implements SOCKS4[A] and SOCKS5.<br>It does not, however, implement the BIND commands, so you cannot .</br></remarks>
internal class ProxySocket : Socket
{
/// <summary>
/// Initializes a new instance of the ProxySocket class.
/// </summary>
/// <param name="addressFamily">One of the AddressFamily values.</param>
/// <param name="socketType">One of the SocketType values.</param>
/// <param name="protocolType">One of the ProtocolType values.</param>
/// <exception cref="SocketException">The combination of addressFamily, socketType, and protocolType results in an invalid socket.</exception>
public ProxySocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) : this(addressFamily, socketType, protocolType, "") { }
/// <summary>
/// Initializes a new instance of the ProxySocket class.
/// </summary>
/// <param name="addressFamily">One of the AddressFamily values.</param>
/// <param name="socketType">One of the SocketType values.</param>
/// <param name="protocolType">One of the ProtocolType values.</param>
/// <param name="proxyUsername">The username to use when authenticating with the proxy server.</param>
/// <exception cref="SocketException">The combination of addressFamily, socketType, and protocolType results in an invalid socket.</exception>
/// <exception cref="ArgumentNullException"><c>proxyUsername</c> is null.</exception>
public ProxySocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, string proxyUsername) : this(addressFamily, socketType, protocolType, proxyUsername, "") { }
/// <summary>
/// Initializes a new instance of the ProxySocket class.
/// </summary>
/// <param name="addressFamily">One of the AddressFamily values.</param>
/// <param name="socketType">One of the SocketType values.</param>
/// <param name="protocolType">One of the ProtocolType values.</param>
/// <param name="proxyUsername">The username to use when authenticating with the proxy server.</param>
/// <param name="proxyPassword">The password to use when authenticating with the proxy server.</param>
/// <exception cref="SocketException">The combination of addressFamily, socketType, and protocolType results in an invalid socket.</exception>
/// <exception cref="ArgumentNullException"><c>proxyUsername</c> -or- <c>proxyPassword</c> is null.</exception>
public ProxySocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, string proxyUsername, string proxyPassword)
: base(addressFamily, socketType, protocolType)
{
ProxyUser = proxyUsername;
ProxyPass = proxyPassword;
ToThrow = new InvalidOperationException();
}
/// <summary>
/// Establishes a connection to a remote device.
/// </summary>
/// <param name="remoteEP">An EndPoint that represents the remote device.</param>
/// <exception cref="ArgumentNullException">The remoteEP parameter is a null reference (Nothing in Visual Basic).</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
/// <exception cref="ProxyException">An error occured while talking to the proxy server.</exception>
public new void Connect(EndPoint remoteEP)
{
if (remoteEP == null)
throw new ArgumentNullException("<remoteEP> cannot be null.");
if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null)
base.Connect(remoteEP);
else
{
base.Connect(ProxyEndPoint);
if (ProxyType == ProxyTypes.Socks4)
(new Socks4Handler(this, ProxyUser)).Negotiate((IPEndPoint)remoteEP);
else if (ProxyType == ProxyTypes.Socks5)
(new Socks5Handler(this, ProxyUser, ProxyPass)).Negotiate((IPEndPoint)remoteEP);
}
}
/// <summary>
/// Establishes a connection to a remote device.
/// </summary>
/// <param name="host">The remote host to connect to.</param>
/// <param name="port">The remote port to connect to.</param>
/// <exception cref="ArgumentNullException">The host parameter is a null reference (Nothing in Visual Basic).</exception>
/// <exception cref="ArgumentException">The port parameter is invalid.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
/// <exception cref="ProxyException">An error occured while talking to the proxy server.</exception>
/// <remarks>If you use this method with a SOCKS4 server, it will let the server resolve the hostname. Not all SOCKS4 servers support this 'remote DNS' though.</remarks>
public void Connect(string host, int port)
{
if (host == null)
throw new ArgumentNullException("<host> cannot be null.");
if (port <= 0 || port > 65535)
throw new ArgumentException("Invalid port.");
if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null)
base.Connect(new IPEndPoint(Dns.GetHostEntry(host).AddressList[0], port));
else
{
base.Connect(ProxyEndPoint);
if (ProxyType == ProxyTypes.Socks4)
(new Socks4Handler(this, ProxyUser)).Negotiate(host, port);
else if (ProxyType == ProxyTypes.Socks5)
(new Socks5Handler(this, ProxyUser, ProxyPass)).Negotiate(host, port);
}
}
/// <summary>
/// Begins an asynchronous request for a connection to a network device.
/// </summary>
/// <param name="remoteEP">An EndPoint that represents the remote device.</param>
/// <param name="callback">The AsyncCallback delegate.</param>
/// <param name="state">An object that contains state information for this request.</param>
/// <returns>An IAsyncResult that references the asynchronous connection.</returns>
/// <exception cref="ArgumentNullException">The remoteEP parameter is a null reference (Nothing in Visual Basic).</exception>
/// <exception cref="SocketException">An operating system error occurs while creating the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public new IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
{
if (remoteEP == null || callback == null)
throw new ArgumentNullException();
if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null)
{
return base.BeginConnect(remoteEP, callback, state);
}
else
{
CallBack = callback;
if (ProxyType == ProxyTypes.Socks4)
{
AsyncResult = (new Socks4Handler(this, ProxyUser)).BeginNegotiate((IPEndPoint)remoteEP, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
return AsyncResult;
}
else if (ProxyType == ProxyTypes.Socks5)
{
AsyncResult = (new Socks5Handler(this, ProxyUser, ProxyPass)).BeginNegotiate((IPEndPoint)remoteEP, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
return AsyncResult;
}
return null;
}
}
/// <summary>
/// Begins an asynchronous request for a connection to a network device.
/// </summary>
/// <param name="host">The host to connect to.</param>
/// <param name="port">The port on the remote host to connect to.</param>
/// <param name="callback">The AsyncCallback delegate.</param>
/// <param name="state">An object that contains state information for this request.</param>
/// <returns>An IAsyncResult that references the asynchronous connection.</returns>
/// <exception cref="ArgumentNullException">The host parameter is a null reference (Nothing in Visual Basic).</exception>
/// <exception cref="ArgumentException">The port parameter is invalid.</exception>
/// <exception cref="SocketException">An operating system error occurs while creating the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public IAsyncResult BeginConnect(string host, int port, AsyncCallback callback, object state)
{
if (host == null || callback == null)
throw new ArgumentNullException();
if (port <= 0 || port > 65535)
throw new ArgumentException();
CallBack = callback;
if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null)
{
RemotePort = port;
AsyncResult = BeginDns(host, new HandShakeComplete(this.OnHandShakeComplete));
return AsyncResult;
}
else
{
if (ProxyType == ProxyTypes.Socks4)
{
AsyncResult = (new Socks4Handler(this, ProxyUser)).BeginNegotiate(host, port, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
return AsyncResult;
}
else if (ProxyType == ProxyTypes.Socks5)
{
AsyncResult = (new Socks5Handler(this, ProxyUser, ProxyPass)).BeginNegotiate(host, port, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint);
return AsyncResult;
}
return null;
}
}
/// <summary>
/// Ends a pending asynchronous connection request.
/// </summary>
/// <param name="asyncResult">Stores state information for this asynchronous operation as well as any user-defined data.</param>
/// <exception cref="ArgumentNullException">The asyncResult parameter is a null reference (Nothing in Visual Basic).</exception>
/// <exception cref="ArgumentException">The asyncResult parameter was not returned by a call to the BeginConnect method.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
/// <exception cref="InvalidOperationException">EndConnect was previously called for the asynchronous connection.</exception>
/// <exception cref="ProxyException">The proxy server refused the connection.</exception>
public new void EndConnect(IAsyncResult asyncResult)
{
if (asyncResult == null)
throw new ArgumentNullException();
if (!asyncResult.IsCompleted)
throw new ArgumentException();
if (ToThrow != null)
throw ToThrow;
return;
}
/// <summary>
/// Begins an asynchronous request to resolve a DNS host name or IP address in dotted-quad notation to an IPAddress instance.
/// </summary>
/// <param name="host">The host to resolve.</param>
/// <param name="callback">The method to call when the hostname has been resolved.</param>
/// <returns>An IAsyncResult instance that references the asynchronous request.</returns>
/// <exception cref="SocketException">There was an error while trying to resolve the host.</exception>
internal IAsyncProxyResult BeginDns(string host, HandShakeComplete callback)
{
try
{
Dns.BeginGetHostEntry(host, new AsyncCallback(this.OnResolved), this);
return new IAsyncProxyResult();
}
catch
{
throw new SocketException();
}
}
/// <summary>
/// Called when the specified hostname has been resolved.
/// </summary>
/// <param name="asyncResult">The result of the asynchronous operation.</param>
private void OnResolved(IAsyncResult asyncResult)
{
try
{
IPHostEntry dns = Dns.EndGetHostEntry(asyncResult);
base.BeginConnect(new IPEndPoint(dns.AddressList[0], RemotePort), new AsyncCallback(this.OnConnect), State);
}
catch (Exception e)
{
OnHandShakeComplete(e);
}
}
/// <summary>
/// Called when the Socket is connected to the remote host.
/// </summary>
/// <param name="asyncResult">The result of the asynchronous operation.</param>
private void OnConnect(IAsyncResult asyncResult)
{
try
{
base.EndConnect(asyncResult);
OnHandShakeComplete(null);
}
catch (Exception e)
{
OnHandShakeComplete(e);
}
}
/// <summary>
/// Called when the Socket has finished talking to the proxy server and is ready to relay data.
/// </summary>
/// <param name="error">The error to throw when the EndConnect method is called.</param>
private void OnHandShakeComplete(Exception error)
{
if (error != null)
this.Close();
ToThrow = error;
AsyncResult.Reset();
if (CallBack != null)
CallBack(AsyncResult);
}
/// <summary>
/// Gets or sets the EndPoint of the proxy server.
/// </summary>
/// <value>An IPEndPoint object that holds the IP address and the port of the proxy server.</value>
public IPEndPoint ProxyEndPoint
{
get
{
return m_ProxyEndPoint;
}
set
{
m_ProxyEndPoint = value;
}
}
/// <summary>
/// Gets or sets the type of proxy server to use.
/// </summary>
/// <value>One of the ProxyTypes values.</value>
public ProxyTypes ProxyType
{
get
{
return m_ProxyType;
}
set
{
m_ProxyType = value;
}
}
/// <summary>
/// Gets or sets a user-defined object.
/// </summary>
/// <value>The user-defined object.</value>
private object State
{
get
{
return m_State;
}
set
{
m_State = value;
}
}
/// <summary>
/// Gets or sets the username to use when authenticating with the proxy.
/// </summary>
/// <value>A string that holds the username that's used when authenticating with the proxy.</value>
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
public string ProxyUser
{
get
{
return m_ProxyUser;
}
set
{
if (value == null)
throw new ArgumentNullException();
m_ProxyUser = value;
}
}
/// <summary>
/// Gets or sets the password to use when authenticating with the proxy.
/// </summary>
/// <value>A string that holds the password that's used when authenticating with the proxy.</value>
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
public string ProxyPass
{
get
{
return m_ProxyPass;
}
set
{
if (value == null)
throw new ArgumentNullException();
m_ProxyPass = value;
}
}
/// <summary>
/// Gets or sets the asynchronous result object.
/// </summary>
/// <value>An instance of the IAsyncProxyResult class.</value>
private IAsyncProxyResult AsyncResult
{
get
{
return m_AsyncResult;
}
set
{
m_AsyncResult = value;
}
}
/// <summary>
/// Gets or sets the exception to throw when the EndConnect method is called.
/// </summary>
/// <value>An instance of the Exception class (or subclasses of Exception).</value>
private Exception ToThrow
{
get
{
return m_ToThrow;
}
set
{
m_ToThrow = value;
}
}
/// <summary>
/// Gets or sets the remote port the user wants to connect to.
/// </summary>
/// <value>An integer that specifies the port the user wants to connect to.</value>
private int RemotePort
{
get
{
return m_RemotePort;
}
set
{
m_RemotePort = value;
}
}
// private variables
/// <summary>Holds the value of the State property.</summary>
private object m_State;
/// <summary>Holds the value of the ProxyEndPoint property.</summary>
private IPEndPoint m_ProxyEndPoint = null;
/// <summary>Holds the value of the ProxyType property.</summary>
private ProxyTypes m_ProxyType = ProxyTypes.None;
/// <summary>Holds the value of the ProxyUser property.</summary>
private string m_ProxyUser = null;
/// <summary>Holds the value of the ProxyPass property.</summary>
private string m_ProxyPass = null;
/// <summary>Holds a pointer to the method that should be called when the Socket is connected to the remote device.</summary>
private AsyncCallback CallBack = null;
/// <summary>Holds the value of the AsyncResult property.</summary>
private IAsyncProxyResult m_AsyncResult;
/// <summary>Holds the value of the ToThrow property.</summary>
private Exception m_ToThrow = null;
/// <summary>Holds the value of the RemotePort property.</summary>
private int m_RemotePort;
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/Socks4Handler.cs
0,0 → 1,234
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
 
namespace Org.Mentalis.Network.ProxySocket {
/// <summary>
/// Implements the SOCKS4[A] protocol.
/// </summary>
internal sealed class Socks4Handler : SocksHandler {
/// <summary>
/// Initilizes a new instance of the SocksHandler class.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
/// <param name="user">The username to use when authenticating with the server.</param>
/// <exception cref="ArgumentNullException"><c>server</c> -or- <c>user</c> is null.</exception>
public Socks4Handler(Socket server, string user) : base(server, user) {}
/// <summary>
/// Creates an array of bytes that has to be sent when the user wants to connect to a specific host/port combination.
/// </summary>
/// <param name="host">The host to connect to.</param>
/// <param name="port">The port to connect to.</param>
/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific host/port combination.</returns>
/// <remarks>Resolving the host name will be done at server side. Do note that some SOCKS4 servers do not implement this functionality.</remarks>
/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
/// <exception cref="ArgumentException"><c>port</c> is invalid.</exception>
private byte[] GetHostPortBytes(string host, int port) {
if (host == null)
throw new ArgumentNullException();
if (port <= 0 || port > 65535)
throw new ArgumentException();
byte [] connect = new byte[10 + Username.Length + host.Length];
connect[0] = 4;
connect[1] = 1;
Array.Copy(PortToBytes(port), 0, connect, 2, 2);
connect[4] = connect[5] = connect[6] = 0;
connect[7] = 1;
Array.Copy(Encoding.ASCII.GetBytes(Username), 0, connect, 8, Username.Length);
connect[8 + Username.Length] = 0;
Array.Copy(Encoding.ASCII.GetBytes(host), 0, connect, 9 + Username.Length, host.Length);
connect[9 + Username.Length + host.Length] = 0;
return connect;
}
/// <summary>
/// Creates an array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.
/// </summary>
/// <param name="remoteEP">The IPEndPoint to connect to.</param>
/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.</returns>
/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
private byte[] GetEndPointBytes(IPEndPoint remoteEP) {
if (remoteEP == null)
throw new ArgumentNullException();
byte [] connect = new byte[9 + Username.Length];
connect[0] = 4;
connect[1] = 1;
Array.Copy(PortToBytes(remoteEP.Port), 0, connect, 2, 2);
Array.Copy(remoteEP.Address.GetAddressBytes(), 0, connect, 4, 4);
Array.Copy(Encoding.ASCII.GetBytes(Username), 0, connect, 8, Username.Length);
connect[8 + Username.Length] = 0;
return connect;
}
/// <summary>
/// Starts negotiating with the SOCKS server.
/// </summary>
/// <param name="host">The host to connect to.</param>
/// <param name="port">The port to connect to.</param>
/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
/// <exception cref="ArgumentException"><c>port</c> is invalid.</exception>
/// <exception cref="ProxyException">The proxy rejected the request.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public override void Negotiate(string host, int port) {
Negotiate(GetHostPortBytes(host, port));
}
/// <summary>
/// Starts negotiating with the SOCKS server.
/// </summary>
/// <param name="remoteEP">The IPEndPoint to connect to.</param>
/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
/// <exception cref="ProxyException">The proxy rejected the request.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
public override void Negotiate(IPEndPoint remoteEP) {
Negotiate(GetEndPointBytes(remoteEP));
}
/// <summary>
/// Starts negotiating with the SOCKS server.
/// </summary>
/// <param name="connect">The bytes to send when trying to authenticate.</param>
/// <exception cref="ArgumentNullException"><c>connect</c> is null.</exception>
/// <exception cref="ArgumentException"><c>connect</c> is too small.</exception>
/// <exception cref="ProxyException">The proxy rejected the request.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
private void Negotiate(byte [] connect) {
if (connect == null)
throw new ArgumentNullException();
if (connect.Length < 2)
throw new ArgumentException();
Server.Send(connect);
byte [] buffer = ReadBytes(8);
if (buffer[1] != 90) {
Server.Close();
throw new ProxyException("Negotiation failed.");
}
}
/// <summary>
/// Starts negotiating asynchronously with a SOCKS proxy server.
/// </summary>
/// <param name="host">The remote server to connect to.</param>
/// <param name="port">The remote port to connect to.</param>
/// <param name="callback">The method to call when the connection has been established.</param>
/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
public override IAsyncProxyResult BeginNegotiate(string host, int port, HandShakeComplete callback, IPEndPoint proxyEndPoint) {
ProtocolComplete = callback;
Buffer = GetHostPortBytes(host, port);
Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server);
AsyncResult = new IAsyncProxyResult();
return AsyncResult;
}
/// <summary>
/// Starts negotiating asynchronously with a SOCKS proxy server.
/// </summary>
/// <param name="remoteEP">An IPEndPoint that represents the remote device.</param>
/// <param name="callback">The method to call when the connection has been established.</param>
/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
public override IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeComplete callback, IPEndPoint proxyEndPoint) {
ProtocolComplete = callback;
Buffer = GetEndPointBytes(remoteEP);
Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server);
AsyncResult = new IAsyncProxyResult();
return AsyncResult;
}
/// <summary>
/// Called when the Socket is connected to the remote proxy server.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnConnect(IAsyncResult ar) {
try {
Server.EndConnect(ar);
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
Server.BeginSend(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server);
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Called when the Socket has sent the handshake data.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnSent(IAsyncResult ar) {
try {
if (Server.EndSend(ar) < Buffer.Length) {
ProtocolComplete(new SocketException());
return;
}
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
Buffer = new byte[8];
Received = 0;
Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Called when the Socket has received a reply from the remote proxy server.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnReceive(IAsyncResult ar) {
try {
int received = Server.EndReceive(ar);
if (received <= 0) {
ProtocolComplete(new SocketException());
return;
}
Received += received;
if (Received == 8) {
if (Buffer[1] == 90)
ProtocolComplete(null);
else {
Server.Close();
ProtocolComplete(new ProxyException("Negotiation failed."));
}
} else {
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
}
} catch (Exception e) {
ProtocolComplete(e);
}
}
}
}
 
 
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/Socks5Handler.cs
0,0 → 1,420
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Org.Mentalis.Network.ProxySocket.Authentication;
 
namespace Org.Mentalis.Network.ProxySocket {
/// <summary>
/// Implements the SOCKS5 protocol.
/// </summary>
internal sealed class Socks5Handler : SocksHandler {
/// <summary>
/// Initiliazes a new Socks5Handler instance.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
/// <exception cref="ArgumentNullException"><c>server</c> is null.</exception>
public Socks5Handler(Socket server) : this(server, "") {}
/// <summary>
/// Initiliazes a new Socks5Handler instance.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
/// <param name="user">The username to use.</param>
/// <exception cref="ArgumentNullException"><c>server</c> -or- <c>user</c> is null.</exception>
public Socks5Handler(Socket server, string user) : this(server, user, "") {}
/// <summary>
/// Initiliazes a new Socks5Handler instance.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
/// <param name="user">The username to use.</param>
/// <param name="pass">The password to use.</param>
/// <exception cref="ArgumentNullException"><c>server</c> -or- <c>user</c> -or- <c>pass</c> is null.</exception>
public Socks5Handler(Socket server, string user, string pass) : base(server, user) {
Password = pass;
}
/// <summary>
/// Starts the synchronous authentication process.
/// </summary>
/// <exception cref="ProxyException">Authentication with the proxy server failed.</exception>
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
private void Authenticate() {
Server.Send(new byte [] {5, 2, 0, 2});
byte[] buffer = ReadBytes(2);
if (buffer[1] == 255)
throw new ProxyException("No authentication method accepted.");
AuthMethod authenticate;
switch (buffer[1]) {
case 0:
authenticate = new AuthNone(Server);
break;
case 2:
authenticate = new AuthUserPass(Server, Username, Password);
break;
default:
throw new ProtocolViolationException();
}
authenticate.Authenticate();
}
/// <summary>
/// Creates an array of bytes that has to be sent when the user wants to connect to a specific host/port combination.
/// </summary>
/// <param name="host">The host to connect to.</param>
/// <param name="port">The port to connect to.</param>
/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific host/port combination.</returns>
/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
/// <exception cref="ArgumentException"><c>port</c> or <c>host</c> is invalid.</exception>
private byte[] GetHostPortBytes(string host, int port) {
if (host == null)
throw new ArgumentNullException();
if (port <= 0 || port > 65535 || host.Length > 255)
throw new ArgumentException();
byte [] connect = new byte[7 + host.Length];
connect[0] = 5;
connect[1] = 1;
connect[2] = 0; //reserved
connect[3] = 3;
connect[4] = (byte)host.Length;
Array.Copy(Encoding.ASCII.GetBytes(host), 0, connect, 5, host.Length);
Array.Copy(PortToBytes(port), 0, connect, host.Length + 5, 2);
return connect;
}
/// <summary>
/// Creates an array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.
/// </summary>
/// <param name="remoteEP">The IPEndPoint to connect to.</param>
/// <returns>An array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint.</returns>
/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
private byte[] GetEndPointBytes(IPEndPoint remoteEP) {
if (remoteEP == null)
throw new ArgumentNullException();
byte [] connect = new byte[10];
connect[0] = 5;
connect[1] = 1;
connect[2] = 0; //reserved
connect[3] = 1;
 
Array.Copy(remoteEP.Address.GetAddressBytes(), 0, connect, 4, 4);
Array.Copy(PortToBytes(remoteEP.Port), 0, connect, 8, 2);
return connect;
}
/// <summary>
/// Starts negotiating with the SOCKS server.
/// </summary>
/// <param name="host">The host to connect to.</param>
/// <param name="port">The port to connect to.</param>
/// <exception cref="ArgumentNullException"><c>host</c> is null.</exception>
/// <exception cref="ArgumentException"><c>port</c> is invalid.</exception>
/// <exception cref="ProxyException">The proxy rejected the request.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
public override void Negotiate(string host, int port) {
Negotiate(GetHostPortBytes(host, port));
}
/// <summary>
/// Starts negotiating with the SOCKS server.
/// </summary>
/// <param name="remoteEP">The IPEndPoint to connect to.</param>
/// <exception cref="ArgumentNullException"><c>remoteEP</c> is null.</exception>
/// <exception cref="ProxyException">The proxy rejected the request.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
public override void Negotiate(IPEndPoint remoteEP) {
Negotiate(GetEndPointBytes(remoteEP));
}
/// <summary>
/// Starts negotiating with the SOCKS server.
/// </summary>
/// <param name="connect">The bytes to send when trying to authenticate.</param>
/// <exception cref="ArgumentNullException"><c>connect</c> is null.</exception>
/// <exception cref="ArgumentException"><c>connect</c> is too small.</exception>
/// <exception cref="ProxyException">The proxy rejected the request.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
/// <exception cref="ProtocolViolationException">The proxy server uses an invalid protocol.</exception>
private void Negotiate(byte[] connect) {
Authenticate();
Server.Send(connect);
byte[] buffer = ReadBytes(4);
if (buffer[1] != 0) {
Server.Close();
throw new ProxyException(buffer[1]);
}
switch(buffer[3]) {
case 1:
buffer = ReadBytes(6); //IPv4 address with port
break;
case 3:
buffer = ReadBytes(1);
buffer = ReadBytes(buffer[0] + 2); //domain name with port
break;
case 4:
buffer = ReadBytes(18); //IPv6 address with port
break;
default:
Server.Close();
throw new ProtocolViolationException();
}
}
/// <summary>
/// Starts negotiating asynchronously with the SOCKS server.
/// </summary>
/// <param name="host">The host to connect to.</param>
/// <param name="port">The port to connect to.</param>
/// <param name="callback">The method to call when the negotiation is complete.</param>
/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
public override IAsyncProxyResult BeginNegotiate(string host, int port, HandShakeComplete callback, IPEndPoint proxyEndPoint) {
ProtocolComplete = callback;
HandShake = GetHostPortBytes(host, port);
Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server);
AsyncResult = new IAsyncProxyResult();
return AsyncResult;
}
/// <summary>
/// Starts negotiating asynchronously with the SOCKS server.
/// </summary>
/// <param name="remoteEP">An IPEndPoint that represents the remote device.</param>
/// <param name="callback">The method to call when the negotiation is complete.</param>
/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
public override IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeComplete callback, IPEndPoint proxyEndPoint) {
ProtocolComplete = callback;
HandShake = GetEndPointBytes(remoteEP);
Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server);
AsyncResult = new IAsyncProxyResult();
return AsyncResult;
}
/// <summary>
/// Called when the socket is connected to the remote server.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnConnect(IAsyncResult ar) {
try {
Server.EndConnect(ar);
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
Server.BeginSend(new byte [] {5, 2, 0, 2}, 0, 4, SocketFlags.None, new AsyncCallback(this.OnAuthSent), Server);
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Called when the authentication bytes have been sent.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnAuthSent(IAsyncResult ar) {
try {
Server.EndSend(ar);
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
Buffer = new byte[1024];
Received = 0;
Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnAuthReceive), Server);
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Called when an authentication reply has been received.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnAuthReceive(IAsyncResult ar) {
try {
Received += Server.EndReceive(ar);
if (Received <= 0)
throw new SocketException();
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
if (Received < 2) {
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnAuthReceive), Server);
} else {
AuthMethod authenticate;
switch(Buffer[1]) {
case 0:
authenticate = new AuthNone(Server);
break;
case 2:
authenticate = new AuthUserPass(Server, Username, Password);
break;
default:
ProtocolComplete(new SocketException());
return;
}
authenticate.BeginAuthenticate(new HandShakeComplete(this.OnAuthenticated));
}
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Called when the socket has been successfully authenticated with the server.
/// </summary>
/// <param name="e">The exception that has occured while authenticating, or <em>null</em> if no error occured.</param>
private void OnAuthenticated(Exception e) {
if (e != null) {
ProtocolComplete(e);
return;
}
try {
Server.BeginSend(HandShake, 0, HandShake.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server);
} catch (Exception ex) {
ProtocolComplete(ex);
}
}
/// <summary>
/// Called when the connection request has been sent.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnSent(IAsyncResult ar) {
try {
Server.EndSend(ar);
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
Buffer = new byte[5];
Received = 0;
Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Called when a connection reply has been received.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnReceive(IAsyncResult ar) {
try {
Received += Server.EndReceive(ar);
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
if (Received == Buffer.Length)
ProcessReply(Buffer);
else
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server);
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Processes the received reply.
/// </summary>
/// <param name="buffer">The received reply</param>
/// <exception cref="ProtocolViolationException">The received reply is invalid.</exception>
private void ProcessReply(byte[] buffer) {
switch(buffer[3]) {
case 1:
Buffer = new byte[5]; //IPv4 address with port - 1 byte
break;
case 3:
Buffer = new byte[buffer[4] + 2]; //domain name with port
break;
case 4:
buffer = new byte[17]; //IPv6 address with port - 1 byte
break;
default:
throw new ProtocolViolationException();
}
Received = 0;
Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReadLast), Server);
}
/// <summary>
/// Called when the last bytes are read from the socket.
/// </summary>
/// <param name="ar">Stores state information for this asynchronous operation as well as any user-defined data.</param>
private void OnReadLast(IAsyncResult ar) {
try {
Received += Server.EndReceive(ar);
} catch (Exception e) {
ProtocolComplete(e);
return;
}
try {
if (Received == Buffer.Length)
ProtocolComplete(null);
else
Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReadLast), Server);
} catch (Exception e) {
ProtocolComplete(e);
}
}
/// <summary>
/// Gets or sets the password to use when authenticating with the SOCKS5 server.
/// </summary>
/// <value>The password to use when authenticating with the SOCKS5 server.</value>
private string Password {
get {
return m_Password;
}
set {
if (value == null)
throw new ArgumentNullException();
m_Password = value;
}
}
/// <summary>
/// Gets or sets the bytes to use when sending a connect request to the proxy server.
/// </summary>
/// <value>The array of bytes to use when sending a connect request to the proxy server.</value>
private byte[] HandShake {
get {
return m_HandShake;
}
set {
m_HandShake = value;
}
}
// private variables
/// <summary>Holds the value of the Password property.</summary>
private string m_Password;
/// <summary>Holds the value of the HandShake property.</summary>
private byte[] m_HandShake;
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/SocksHandler.cs
0,0 → 1,192
/*
Copyright © 2002, The KPD-Team
All rights reserved.
http://www.mentalis.org/
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
 
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
 
- Neither the name of the KPD-Team, nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
using System;
using System.Net;
using System.Net.Sockets;
 
namespace Org.Mentalis.Network.ProxySocket {
/// <summary>
/// References the callback method to be called when the protocol negotiation is completed.
/// </summary>
internal delegate void HandShakeComplete(Exception error);
/// <summary>
/// Implements a specific version of the SOCKS protocol. This is an abstract class; it must be inherited.
/// </summary>
internal abstract class SocksHandler {
/// <summary>
/// Initilizes a new instance of the SocksHandler class.
/// </summary>
/// <param name="server">The socket connection with the proxy server.</param>
/// <param name="user">The username to use when authenticating with the server.</param>
/// <exception cref="ArgumentNullException"><c>server</c> -or- <c>user</c> is null.</exception>
public SocksHandler(Socket server, string user) {
Server = server;
Username = user;
}
/// <summary>
/// Converts a port number to an array of bytes.
/// </summary>
/// <param name="port">The port to convert.</param>
/// <returns>An array of two bytes that represents the specified port.</returns>
protected byte[] PortToBytes(int port) {
byte [] ret = new byte[2];
ret[0] = (byte)(port / 256);
ret[1] = (byte)(port % 256);
return ret;
}
 
/// <summary>
/// Reads a specified number of bytes from the Server socket.
/// </summary>
/// <param name="count">The number of bytes to return.</param>
/// <returns>An array of bytes.</returns>
/// <exception cref="ArgumentException">The number of bytes to read is invalid.</exception>
/// <exception cref="SocketException">An operating system error occurs while accessing the Socket.</exception>
/// <exception cref="ObjectDisposedException">The Socket has been closed.</exception>
protected byte[] ReadBytes(int count) {
if (count <= 0)
throw new ArgumentException();
byte[] buffer = new byte[count];
int received = 0;
while(received != count) {
received += Server.Receive(buffer, received, count - received, SocketFlags.None);
}
return buffer;
}
/// <summary>
/// Gets or sets the socket connection with the proxy server.
/// </summary>
/// <value>A Socket object that represents the connection with the proxy server.</value>
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
protected Socket Server {
get {
return m_Server;
}
set {
if (value == null)
throw new ArgumentNullException();
m_Server = value;
}
}
/// <summary>
/// Gets or sets the username to use when authenticating with the proxy server.
/// </summary>
/// <value>A string that holds the username to use when authenticating with the proxy server.</value>
/// <exception cref="ArgumentNullException">The specified value is null.</exception>
protected string Username {
get {
return m_Username;
}
set {
if (value == null)
throw new ArgumentNullException();
m_Username = value;
}
}
/// <summary>
/// Gets or sets the return value of the BeginConnect call.
/// </summary>
/// <value>An IAsyncProxyResult object that is the return value of the BeginConnect call.</value>
protected IAsyncProxyResult AsyncResult {
get {
return m_AsyncResult;
}
set {
m_AsyncResult = value;
}
}
/// <summary>
/// Gets or sets a byte buffer.
/// </summary>
/// <value>An array of bytes.</value>
protected byte[] Buffer {
get {
return m_Buffer;
}
set {
m_Buffer = value;
}
}
/// <summary>
/// Gets or sets the number of bytes that have been received from the remote proxy server.
/// </summary>
/// <value>An integer that holds the number of bytes that have been received from the remote proxy server.</value>
protected int Received {
get {
return m_Received;
}
set {
m_Received = value;
}
}
// private variables
/// <summary>Holds the value of the Server property.</summary>
private Socket m_Server;
/// <summary>Holds the value of the Username property.</summary>
private string m_Username;
/// <summary>Holds the value of the AsyncResult property.</summary>
private IAsyncProxyResult m_AsyncResult;
/// <summary>Holds the value of the Buffer property.</summary>
private byte[] m_Buffer;
/// <summary>Holds the value of the Received property.</summary>
private int m_Received;
/// <summary>Holds the address of the method to call when the SOCKS protocol has been completed.</summary>
protected HandShakeComplete ProtocolComplete;
/// <summary>
/// Starts negotiating with a SOCKS proxy server.
/// </summary>
/// <param name="host">The remote server to connect to.</param>
/// <param name="port">The remote port to connect to.</param>
public abstract void Negotiate(string host, int port);
/// <summary>
/// Starts negotiating with a SOCKS proxy server.
/// </summary>
/// <param name="remoteEP">The remote endpoint to connect to.</param>
public abstract void Negotiate(IPEndPoint remoteEP);
/// <summary>
/// Starts negotiating asynchronously with a SOCKS proxy server.
/// </summary>
/// <param name="remoteEP">An IPEndPoint that represents the remote device. </param>
/// <param name="callback">The method to call when the connection has been established.</param>
/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
public abstract IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeComplete callback, IPEndPoint proxyEndPoint);
/// <summary>
/// Starts negotiating asynchronously with a SOCKS proxy server.
/// </summary>
/// <param name="host">The remote server to connect to.</param>
/// <param name="port">The remote port to connect to.</param>
/// <param name="callback">The method to call when the connection has been established.</param>
/// <param name="proxyEndPoint">The IPEndPoint of the SOCKS proxy server.</param>
/// <returns>An IAsyncProxyResult that references the asynchronous connection.</returns>
public abstract IAsyncProxyResult BeginNegotiate(string host, int port, HandShakeComplete callback, IPEndPoint proxyEndPoint);
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/SocksProxySocket/SocksHttpWebRequest.cs
0,0 → 1,413
using System;
using System.Collections.Generic;
using System.Text;
 
namespace GMap.NET.Internals
{
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Org.Mentalis.Network.ProxySocket; // http://www.mentalis.org/soft/class.qpx?id=9
 
/// <summary>
/// http://ditrans.blogspot.com/2009/03/making-witty-work-with-socks-proxy.html
/// </summary>
internal class SocksHttpWebRequest : WebRequest
{
#region Member Variables
 
private readonly Uri _requestUri;
private WebHeaderCollection _requestHeaders;
private string _method;
private SocksHttpWebResponse _response;
private string _requestMessage;
private byte[] _requestContentBuffer;
 
// darn MS for making everything internal (yeah, I'm talking about you, System.net.KnownHttpVerb)
static readonly StringCollection validHttpVerbs =
new StringCollection { "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "OPTIONS" };
 
#endregion
 
#region Constructor
 
private SocksHttpWebRequest(Uri requestUri)
{
_requestUri = requestUri;
}
 
#endregion
 
#region WebRequest Members
 
public override WebResponse GetResponse()
{
if (Proxy == null)
{
throw new InvalidOperationException("Proxy property cannot be null.");
}
if (String.IsNullOrEmpty(Method))
{
throw new InvalidOperationException("Method has not been set.");
}
 
if (RequestSubmitted)
{
return _response;
}
_response = InternalGetResponse();
RequestSubmitted = true;
return _response;
}
 
public override Uri RequestUri
{
get
{
return _requestUri;
}
}
 
public override IWebProxy Proxy
{
get;
set;
}
 
public override WebHeaderCollection Headers
{
get
{
if (_requestHeaders == null)
{
_requestHeaders = new WebHeaderCollection();
}
return _requestHeaders;
}
set
{
if (RequestSubmitted)
{
throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
}
_requestHeaders = value;
}
}
 
public bool RequestSubmitted
{
get;
private set;
}
 
public override string Method
{
get
{
return _method ?? "GET";
}
set
{
if (validHttpVerbs.Contains(value))
{
_method = value;
}
else
{
throw new ArgumentOutOfRangeException("value", string.Format("'{0}' is not a known HTTP verb.", value));
}
}
}
 
public override long ContentLength
{
get;
set;
}
 
public override string ContentType
{
get;
set;
}
 
public override Stream GetRequestStream()
{
if (RequestSubmitted)
{
throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
}
 
if (_requestContentBuffer == null)
{
_requestContentBuffer = new byte[ContentLength];
}
else if (ContentLength == default(long))
{
_requestContentBuffer = new byte[int.MaxValue];
}
else if (_requestContentBuffer.Length != ContentLength)
{
Array.Resize(ref _requestContentBuffer, (int)ContentLength);
}
return new MemoryStream(_requestContentBuffer);
}
 
#endregion
 
#region Methods
 
public static new WebRequest Create(string requestUri)
{
return new SocksHttpWebRequest(new Uri(requestUri));
}
 
public static new WebRequest Create(Uri requestUri)
{
return new SocksHttpWebRequest(requestUri);
}
 
private string BuildHttpRequestMessage()
{
if (RequestSubmitted)
{
throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
}
 
var message = new StringBuilder();
 
message.AppendFormat("{0} {1} HTTP/1.0\r\nHost: {2}\r\n", Method, RequestUri.PathAndQuery, RequestUri.Host);
 
// add the headers
foreach (var key in Headers.Keys)
{
message.AppendFormat("{0}: {1}\r\n", key, Headers[key.ToString()]);
}
 
if (!string.IsNullOrEmpty(ContentType))
{
message.AppendFormat("Content-Type: {0}\r\n", ContentType);
}
if (ContentLength > 0)
{
message.AppendFormat("Content-Length: {0}\r\n", ContentLength);
}
 
// add a blank line to indicate the end of the headers
message.Append("\r\n");
 
// add content
if (_requestContentBuffer != null && _requestContentBuffer.Length > 0)
{
using (var stream = new MemoryStream(_requestContentBuffer, false))
{
using (var reader = new StreamReader(stream))
{
message.Append(reader.ReadToEnd());
}
}
}
 
return message.ToString();
}
 
private SocksHttpWebResponse InternalGetResponse()
{
MemoryStream data = null;
string header = string.Empty;
 
using (var _socksConnection = new ProxySocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
var proxyUri = Proxy.GetProxy(RequestUri);
var ipAddress = GetProxyIpAddress(proxyUri);
_socksConnection.ProxyEndPoint = new IPEndPoint(ipAddress, proxyUri.Port);
_socksConnection.ProxyType = ProxyTypes.Socks5;
 
// open connection
_socksConnection.Connect(RequestUri.Host, 80);
 
// send an HTTP request
_socksConnection.Send(Encoding.UTF8.GetBytes(RequestMessage));
 
// read the HTTP reply
var buffer = new byte[1024 * 4];
int bytesReceived = 0;
bool headerDone = false;
 
while ((bytesReceived = _socksConnection.Receive(buffer)) > 0)
{
if (!headerDone)
{
var headPart = Encoding.UTF8.GetString(buffer, 0, bytesReceived > 1024 ? 1024 : bytesReceived);
var indexOfFirstBlankLine = headPart.IndexOf("\r\n\r\n");
if (indexOfFirstBlankLine > 0)
{
headPart = headPart.Substring(0, indexOfFirstBlankLine);
header += headPart;
headerDone = true;
 
var headerPartLength = Encoding.UTF8.GetByteCount(headPart) + 4;
 
// 0123456789
// ----
if (headerPartLength < bytesReceived)
{
data = new MemoryStream();
data.Write(buffer, headerPartLength, bytesReceived - headerPartLength);
}
}
else
{
header += headPart;
}
}
else
{
if (data == null)
{
data = new MemoryStream();
}
data.Write(buffer, 0, bytesReceived);
}
}
 
if (data != null)
{
data.Position = 0;
}
}
 
return new SocksHttpWebResponse(data, header);
}
 
private static IPAddress GetProxyIpAddress(Uri proxyUri)
{
IPAddress ipAddress;
if (!IPAddress.TryParse(proxyUri.Host, out ipAddress))
{
try
{
return Dns.GetHostEntry(proxyUri.Host).AddressList[0];
}
catch (Exception e)
{
throw new InvalidOperationException(
string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", proxyUri.Host), e);
}
}
return ipAddress;
}
 
#endregion
 
#region Properties
 
public string RequestMessage
{
get
{
if (string.IsNullOrEmpty(_requestMessage))
{
_requestMessage = BuildHttpRequestMessage();
}
return _requestMessage;
}
}
 
#endregion
 
}
 
internal class SocksHttpWebResponse : WebResponse
{
 
#region Member Variables
 
WebHeaderCollection _httpResponseHeaders;
MemoryStream data;
 
public override long ContentLength
{
get;
set;
}
 
public override string ContentType
{
get;
set;
}
 
#endregion
 
#region Constructors
 
public SocksHttpWebResponse(MemoryStream data, string headers)
{
this.data = data;
 
var headerValues = headers.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
 
// ignore the first line in the header since it is the HTTP response code
for (int i = 1; i < headerValues.Length; i++)
{
var headerEntry = headerValues[i].Split(new[] { ':' });
Headers.Add(headerEntry[0], headerEntry[1]);
 
switch (headerEntry[0])
{
case "Content-Type":
{
ContentType = headerEntry[1];
}
break;
 
case "Content-Length":
{
long r = 0;
if(long.TryParse(headerEntry[1], out r))
{
ContentLength = r;
}
}
break;
}
}
}
 
#endregion
 
#region WebResponse Members
 
public override Stream GetResponseStream()
{
return data != null ? data : Stream.Null;
}
 
public override void Close()
{
if (data != null)
{
data.Close();
}
/* the base implementation throws an exception */
}
 
public override WebHeaderCollection Headers
{
get
{
if (_httpResponseHeaders == null)
{
_httpResponseHeaders = new WebHeaderCollection();
}
return _httpResponseHeaders;
}
}
 
#endregion
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/Stuff.cs
0,0 → 1,254

namespace GMap.NET.Internals
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
 
/// <summary>
/// etc functions...
/// </summary>
internal class Stuff
{
public static string EnumToString(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute), false);
 
return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
}
 
[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursorPos")]
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool SetCursorPos(int X, int Y);
 
public static readonly Random random = new System.Random();
 
public static void Shuffle<T>(List<T> deck)
{
int N = deck.Count;
 
for(int i = 0; i < N; ++i)
{
int r = i + (int)(random.Next(N - i));
T t = deck[r];
deck[r] = deck[i];
deck[i] = t;
}
}
 
public static MemoryStream CopyStream(Stream inputStream, bool SeekOriginBegin)
{
const int readSize = 32 * 1024;
byte[] buffer = new byte[readSize];
MemoryStream ms = new MemoryStream();
{
int count = 0;
while((count = inputStream.Read(buffer, 0, readSize)) > 0)
{
ms.Write(buffer, 0, count);
}
}
buffer = null;
if(SeekOriginBegin)
{
inputStream.Seek(0, SeekOrigin.Begin);
}
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
 
public static bool IsRunningOnVistaOrLater()
{
OperatingSystem os = Environment.OSVersion;
 
if(os.Platform == PlatformID.Win32NT)
{
Version vs = os.Version;
 
if(vs.Major >= 6 && vs.Minor >= 0)
{
return true;
}
}
 
return false;
}
 
public static bool IsRunningOnWin7orLater()
{
OperatingSystem os = Environment.OSVersion;
 
if(os.Platform == PlatformID.Win32NT)
{
Version vs = os.Version;
 
if(vs.Major >= 6 && vs.Minor > 0)
{
return true;
}
}
 
return false;
}
 
public static void RemoveInvalidPathSymbols(ref string url)
{
#if !PocketPC
char[] ilg = Path.GetInvalidFileNameChars();
#else
char[] ilg = new char[41];
for(int i = 0; i < 32; i++)
ilg[i] = (char) i;
 
ilg[32] = '"';
ilg[33] = '<';
ilg[34] = '>';
ilg[35] = '|';
ilg[36] = '?';
ilg[37] = ':';
ilg[38] = '/';
ilg[39] = '\\';
ilg[39] = '*';
#endif
foreach(char c in ilg)
{
url = url.Replace(c, '_');
}
}
 
#region -- encryption --
static string EncryptString(string Message, string Passphrase)
{
byte[] Results;
 
using (var HashProvider = new SHA1CryptoServiceProvider())
{
byte[] TDESKey = HashProvider.ComputeHash(Encoding.UTF8.GetBytes(Passphrase));
Array.Resize(ref TDESKey, 16);
 
using (TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider())
{
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
 
byte[] DataToEncrypt = Encoding.UTF8.GetBytes(Message);
 
// Step 5. Attempt to encrypt the string
try
{
using (ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor())
{
Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
}
}
finally
{
// Clear the TripleDes and Hashprovider services of any sensitive information
TDESAlgorithm.Clear();
HashProvider.Clear();
}
}
}
 
// Step 6. Return the encrypted string as a base64 encoded string
return Convert.ToBase64String(Results);
}
 
static string DecryptString(string Message, string Passphrase)
{
byte[] Results;
 
using (var HashProvider = new SHA1CryptoServiceProvider())
{
byte[] TDESKey = HashProvider.ComputeHash(Encoding.UTF8.GetBytes(Passphrase));
Array.Resize(ref TDESKey, 16);
 
// Step 2. Create a new TripleDESCryptoServiceProvider object
using (TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider())
{
// Step 3. Setup the decoder
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
 
// Step 4. Convert the input string to a byte[]
byte[] DataToDecrypt = Convert.FromBase64String(Message);
 
// Step 5. Attempt to decrypt the string
try
{
using (ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor())
{
Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
}
}
finally
{
// Clear the TripleDes and Hashprovider services of any sensitive information
TDESAlgorithm.Clear();
HashProvider.Clear();
}
}
}
 
// Step 6. Return the decrypted string in UTF8 format
return Encoding.UTF8.GetString(Results, 0, Results.Length);
}
 
public static string EncryptString(string Message)
{
return EncryptString(Message, manifesto);
}
 
public static string GString(string Message)
{
var ret = DecryptString(Message, manifesto);
 
return ret;
}
 
static readonly string manifesto = "GMap.NET is great and Powerful, Free, cross platform, open source .NET control.";
#endregion
}
 
#if PocketPC
static class Monitor
{
static readonly OpenNETCF.Threading.Monitor2 wait = new OpenNETCF.Threading.Monitor2();
 
public static void Enter(Stack<LoadTask> tileLoadQueue)
{
wait.Enter();
}
 
public static void Exit(Stack<LoadTask> tileLoadQueue)
{
wait.Exit();
}
 
public static void Wait(Stack<LoadTask> tileLoadQueue)
{
wait.Wait();
}
 
public static bool Wait(Stack<LoadTask> tileLoadQueue, int WaitForTileLoadThreadTimeout, bool p)
{
wait.Wait();
return true;
}
 
internal static void PulseAll(Stack<LoadTask> tileLoadQueue)
{
wait.PulseAll();
}
}
#endif
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/Tile.cs
0,0 → 1,147

namespace GMap.NET.Internals
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
 
/// <summary>
/// represent tile
/// </summary>
public struct Tile : IDisposable
{
public static readonly Tile Empty = new Tile();
 
GPoint pos;
int zoom;
PureImage[] overlays;
long OverlaysCount;
 
public readonly bool NotEmpty;
 
public Tile(int zoom, GPoint pos)
{
this.NotEmpty = true;
this.zoom = zoom;
this.pos = pos;
this.overlays = null;
this.OverlaysCount = 0;
}
 
public IEnumerable<PureImage> Overlays
{
get
{
#if PocketPC
for (long i = 0, size = OverlaysCount; i < size; i++)
#else
for (long i = 0, size = Interlocked.Read(ref OverlaysCount); i < size; i++)
#endif
{
yield return overlays[i];
}
}
}
 
internal void AddOverlay(PureImage i)
{
if (overlays == null)
{
overlays = new PureImage[4];
}
#if !PocketPC
overlays[Interlocked.Increment(ref OverlaysCount) - 1] = i;
#else
overlays[++OverlaysCount - 1] = i;
#endif
}
 
internal bool HasAnyOverlays
{
get
{
#if PocketPC
return OverlaysCount > 0;
#else
return Interlocked.Read(ref OverlaysCount) > 0;
#endif
}
}
 
public int Zoom
{
get
{
return zoom;
}
private set
{
zoom = value;
}
}
 
public GPoint Pos
{
get
{
return pos;
}
private set
{
pos = value;
}
}
 
#region IDisposable Members
 
public void Dispose()
{
if (overlays != null)
{
#if PocketPC
for (long i = OverlaysCount - 1; i >= 0; i--)
 
#else
for (long i = Interlocked.Read(ref OverlaysCount) - 1; i >= 0; i--)
#endif
{
#if !PocketPC
Interlocked.Decrement(ref OverlaysCount);
#else
OverlaysCount--;
#endif
overlays[i].Dispose();
overlays[i] = null;
}
overlays = null;
}
}
 
#endregion
 
public static bool operator ==(Tile m1, Tile m2)
{
return m1.pos == m2.pos && m1.zoom == m2.zoom;
}
 
public static bool operator !=(Tile m1, Tile m2)
{
return !(m1 == m2);
}
 
public override bool Equals(object obj)
{
if (!(obj is Tile))
return false;
 
Tile comp = (Tile)obj;
return comp.Zoom == this.Zoom && comp.Pos == this.Pos;
}
 
public override int GetHashCode()
{
return zoom ^ pos.GetHashCode();
}
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/TileHttpHost.cs
0,0 → 1,157
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.IO;
using GMap.NET.MapProviders;
 
namespace GMap.NET.Internals
{
internal class TileHttpHost
{
volatile bool listen = false;
TcpListener server;
int port;
 
readonly byte[] responseHeaderBytes;
 
public TileHttpHost()
{
string response = "HTTP/1.0 200 OK\r\nContent-Type: image\r\nConnection: close\r\n\r\n";
responseHeaderBytes = Encoding.ASCII.GetBytes(response);
}
 
public void Stop()
{
if (listen)
{
listen = false;
if (server != null)
{
server.Stop();
}
}
}
 
public void Start(int port)
{
if (server == null)
{
this.port = port;
server = new TcpListener(IPAddress.Any, port);
}
else
{
if (this.port != port)
{
Stop();
this.port = port;
server = null;
server = new TcpListener(IPAddress.Any, port);
}
else
{
if (listen)
{
return;
}
}
}
 
server.Start();
listen = true;
 
Thread t = new Thread(() =>
{
Debug.WriteLine("TileHttpHost: " + server.LocalEndpoint);
 
while (listen)
{
try
{
if (!server.Pending())
{
Thread.Sleep(111);
}
else
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessRequest), server.AcceptTcpClient());
}
}
catch (Exception ex)
{
Debug.WriteLine("TileHttpHost: " + ex);
}
}
 
Debug.WriteLine("TileHttpHost: stoped");
});
 
t.Name = "TileHost";
t.IsBackground = true;
t.Start();
}
 
void ProcessRequest(object p)
{
try
{
using(TcpClient c = p as TcpClient)
{
using(var s = c.GetStream())
{
using(StreamReader r = new StreamReader(s, Encoding.UTF8))
{
var request = r.ReadLine();
 
if(!string.IsNullOrEmpty(request) && request.StartsWith("GET"))
{
//Debug.WriteLine("TileHttpHost: " + request);
 
// http://localhost:88/88888/5/15/11
// GET /8888888888/5/15/11 HTTP/1.1
 
var rq = request.Split(' ');
if(rq.Length >= 2)
{
var ids = rq[1].Split(new char[]{'/'}, StringSplitOptions.RemoveEmptyEntries);
if(ids.Length == 4)
{
int dbId = int.Parse(ids[0]);
int zoom = int.Parse(ids[1]);
int x = int.Parse(ids[2]);
int y = int.Parse(ids[3]);
 
var pr = GMapProviders.TryGetProvider(dbId);
if(pr != null)
{
Exception ex;
var img = GMaps.Instance.GetImageFrom(pr, new GPoint(x, y), zoom, out ex);
if (img != null)
{
using (img)
{
s.Write(responseHeaderBytes, 0, responseHeaderBytes.Length);
img.Data.WriteTo(s);
}
}
}
}
}
}
}
}
c.Close();
}
}
catch (Exception ex)
{
Debug.WriteLine("TileHttpHost, ProcessRequest: " + ex);
}
//Debug.WriteLine("disconnected");
}
}
}
/MKLiveView/v1.0/Source/GMap.NET.Core/GMap.NET.Internals/TileMatrix.cs
0,0 → 1,246

namespace GMap.NET.Internals
{
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
using System;
 
/// <summary>
/// matrix for tiles
/// </summary>
internal class TileMatrix : IDisposable
{
List<Dictionary<GPoint, Tile>> Levels = new List<Dictionary<GPoint, Tile>>(33);
FastReaderWriterLock Lock = new FastReaderWriterLock();
 
public TileMatrix()
{
for(int i = 0; i < Levels.Capacity; i++)
{
Levels.Add(new Dictionary<GPoint, Tile>(55, new GPointComparer()));
}
}
 
public void ClearAllLevels()
{
Lock.AcquireWriterLock();
try
{
foreach(var matrix in Levels)
{
foreach(var t in matrix)
{
t.Value.Dispose();
}
matrix.Clear();
}
}
finally
{
Lock.ReleaseWriterLock();
}
}
 
public void ClearLevel(int zoom)
{
Lock.AcquireWriterLock();
try
{
if(zoom < Levels.Count)
{
var l = Levels[zoom];
 
foreach(var t in l)
{
t.Value.Dispose();
}
 
l.Clear();
}
}
finally
{
Lock.ReleaseWriterLock();
}
}
 
List<KeyValuePair<GPoint, Tile>> tmp = new List<KeyValuePair<GPoint, Tile>>(44);
 
public void ClearLevelAndPointsNotIn(int zoom, List<DrawTile> list)
{
Lock.AcquireWriterLock();
try
{
if(zoom < Levels.Count)
{
var l = Levels[zoom];
 
tmp.Clear();
 
foreach(var t in l)
{
if(!list.Exists(p => p.PosXY == t.Key))
{
tmp.Add(t);
}
}
 
foreach(var r in tmp)
{
l.Remove(r.Key);
r.Value.Dispose();
}
 
tmp.Clear();
}
}
finally
{
Lock.ReleaseWriterLock();
}
}
 
public void ClearLevelsBelove(int zoom)
{
Lock.AcquireWriterLock();
try
{
if(zoom - 1 < Levels.Count)
{
for(int i = zoom - 1; i >= 0; i--)
{
var l = Levels[i];
 
foreach(var t in l)
{
t.Value.Dispose();
}
 
l.Clear();
}
}
}
finally
{
Lock.ReleaseWriterLock();
}
}
 
public void ClearLevelsAbove(int zoom)
{
Lock.AcquireWriterLock();
try
{
if(zoom + 1 < Levels.Count)
{
for(int i = zoom + 1; i < Levels.Count; i++)
{
var l = Levels[i];
 
foreach(var t in l)
{
t.Value.Dispose();
}
 
l.Clear();
}
}
}
finally
{
Lock.ReleaseWriterLock();
}
}
 
public void EnterReadLock()
{
Lock.AcquireReaderLock();
}
 
public void LeaveReadLock()
{
Lock.ReleaseReaderLock();
}
 
public Tile GetTileWithNoLock(int zoom, GPoint p)
{
Tile ret = Tile.Empty;
 
//if(zoom < Levels.Count)
{
Levels[zoom].TryGetValue(p, out ret);
}
 
return ret;
}
 
public Tile GetTileWithReadLock(int zoom, GPoint p)
{
Tile ret = Tile.Empty;
 
Lock.AcquireReaderLock();
try
{
ret = GetTileWithNoLock(zoom, p);
}
finally
{
Lock.ReleaseReaderLock();
}
 
return ret;
}
 
public void SetTile(Tile t)
{
Lock.AcquireWriterLock();
try
{
if(t.Zoom < Levels.Count)
{
Levels[t.Zoom][t.Pos] = t;
}
}
finally
{
Lock.ReleaseWriterLock();
}
}
 
#region IDisposable Members
 
~TileMatrix()
{
Dispose(false);
}
 
void Dispose(bool disposing)
{
if(Lock != null)
{
if(disposing)
{
ClearAllLevels();
}
 
Levels.Clear();
Levels = null;
 
tmp.Clear();
tmp = null;
 
Lock.Dispose();
Lock = null;
}
}
 
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
 
#endregion
}
}