void initUPnP() { for (int i = 0; i < 5; i++) { try { NatUtility.Initialize(); NatUtility.DeviceFound += deviceFound; NatUtility.StartDiscovery(); upnpSem.WaitOne(); NatUtility.StopDiscovery(); break; } catch (Exception e) { System.Threading.Thread.Sleep(1000); if (i < 5) { SystemLog.addEntry("Failed to boot up UPnP. Exception: " + e.Message + ". Trying again..."); } else { SystemLog.addEntry("Giving up on UPnP and running a STUN instead..."); UPnPActive = false; return; } } } }
async Task unMapPorts() { SystemLog.addEntry("Cleaning up UPnP mappings..."); try { if (device == null) { initUPnP(); } externalIPFromUPnP = await device.GetExternalIPAsync(); foreach (Mapping z in await device.GetAllMappingsAsync()) { if (z.Description == Environment.MachineName + " Dimension Mapping") { await device.DeletePortMapAsync(z); SystemLog.addEntry("Successfully deleted UPnP mapping " + z.Description); UPnPActive = true; } } } catch { UPnPActive = false; SystemLog.addEntry("Failed to delete UPnP mapping."); //UPnP probably not supported } }
public FileListDatabase() { SystemLog.addEntry("Loading Databases..."); string folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); folder = Path.Combine(folder, "Dimension"); SystemLog.addEntry("Loading File List..."); fileListPath = Path.Combine(folder, "FileList"); fileList = new RaptorDB.RaptorDB <string>(fileListPath, false); SystemLog.addEntry("Loading Quick Hashes..."); quickHashes = new RaptorDB.RaptorDB <string>(Path.Combine(folder, "QuickHashes"), false); SystemLog.addEntry("Loading Full Hashes..."); fullHashes = new RaptorDB.RaptorDB <string>(Path.Combine(folder, "FullHashes"), false); SystemLog.addEntry("Loading Download Queue..."); downloadQueue = new RaptorDB.RaptorDB <string>(Path.Combine(folder, "DownloadQueue"), false); SystemLog.addEntry("Loading Remote File Lists..."); remoteFileLists = new RaptorDB.RaptorDB <string>(Path.Combine(folder, "RemoteFileLists"), false); SystemLog.addEntry("Loading Search Lists..."); searchListsPath = Path.Combine(folder, "SearchLists"); searchList = new RaptorDB.RaptorDB <string>(searchListsPath, false); SystemLog.addEntry("All Databases Loaded."); }
public Settings() { string folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); folder = Path.Combine(folder, "Dimension"); SystemLog.addEntry("Loading Settings..."); settings = new RaptorDB.RaptorDB <string>(Path.Combine(folder, "Settings"), false); }
public void endPunch(System.Net.IPEndPoint sender) { SystemLog.addEntry("Received BeginPunch from " + sender.ToString()); System.Net.Sockets.Socket udp = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); udp.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0)); SystemLog.addEntry("Bound " + udp.LocalEndPoint.ToString()); byte[] b = App.serializer.serialize(new Commands.EndPunchCommand() { myId = App.theCore.id, port = (ushort)((System.Net.IPEndPoint)udp.LocalEndPoint).Port }); if (isLocal) { foreach (System.Net.IPAddress a in internalAddress) { SystemLog.addEntry("Sent EndPunch to " + new System.Net.IPEndPoint(a, localControlPort)); App.udpSend(b, new System.Net.IPEndPoint(a, localControlPort)); } } else { SystemLog.addEntry("Sent EndPunch to " + actualEndpoint); App.udpSend(b, actualEndpoint); } System.Threading.Thread t = new System.Threading.Thread(delegate() { try { Udt.Socket s = new Udt.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream); s.ReuseAddress = true; s.Bind(udp); s.Rendezvous = true; SystemLog.addEntry("Beginning rendezvous..."); s.Connect(sender); while (s.State == Udt.SocketState.Connecting) { System.Threading.Thread.Sleep(10); } App.theCore.addIncomingConnection(new UdtIncomingConnection(s, udp)); SystemLog.addEntry("Rendezvous successful!"); } catch (Exception e) { SystemLog.addEntry("Error rendezvous'ing to " + sender.ToString() + " - " + e.Message); } }); t.Name = "Rendezvous thread"; t.IsBackground = true; t.Start(); }
void partialUpdate(object sender, System.IO.FileSystemEventArgs e) { lock (updateLock) { quitComplete = false; RootShare[] shares = App.fileListDatabase.getRootShares(); string path = e.FullPath.Replace('\\', '/'); SystemLog.addEntry("Partial filesystem update to " + path.Replace('/', System.IO.Path.DirectorySeparatorChar)); bool isFolder = System.IO.Directory.Exists(path); if (!isFolder) { path = path.Substring(0, path.LastIndexOf('/') + 1); isFolder = System.IO.Directory.Exists(path); } if (isFolder) { System.Threading.Thread t = new System.Threading.Thread(delegate() { foreach (RootShare r in shares) { if (r != null) { if (quitComplete) { return; } if (path.StartsWith(r.fullPath + "/")) { string remaining = path.Replace(System.IO.Path.DirectorySeparatorChar, '/').Substring(r.fullPath.Length + 1); FSListing f = getFSListing("/" + (r.name + "/" + remaining).Trim('/'), true); if (f is Folder) { deleteFolder((Folder)f, false); loadFolder((Folder)f, false, path); //TODO: Update size of everything above this folder } } } } doSave(); if (updateComplete != null) { updateComplete(); } }); t.IsBackground = true; t.Name = "Partial file list update thread"; t.Start(); } } }
public void save() { lock (saveLock) { settings.SaveIndex(); string folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); folder = Path.Combine(folder, "Dimension"); SystemLog.addEntry("Saving Settings..."); /*settings.Dispose(); * settings = new RaptorDB.RaptorDB<string>(Path.Combine(folder, "Settings"), false);*/ } }
System.Net.Sockets.TcpClient attemptConnection() { var t = new System.Net.Sockets.TcpClient(); try { if (isLocal) { t.Connect(new System.Net.IPEndPoint(_actualAddr, localDataPort)); } else { t.Connect(new System.Net.IPEndPoint(_actualAddr, externalDataPort)); } return(t); } catch { } try { if (isLocal) { for (int i = 0; i < internalAddress.Length; i++) { try { t.Connect(new System.Net.IPEndPoint(internalAddress[i], localDataPort)); return(t); } catch { } } } else { t.Connect(new System.Net.IPEndPoint(publicAddress, externalDataPort)); return(t); } } catch { } SystemLog.addEntry("Error reverse connecting to " + _actualAddr); return(null); }
//TODO: When updating shares, chew through File IDs less prodigiously //TODO: Update bottom-up instead of top-down -- so you don't need to do a complete list rebuild every time you change a file public void update(bool urgent) { lock (updateLock) { isUpdating = true; SystemLog.addEntry("Updating all shares" + (urgent ? " (urgently)" : "")); RootShare[] shares = App.fileListDatabase.getRootShares(); foreach (RootShare r in shares) { if (r != null) { updateRootShare(r, urgent); if (System.IO.Directory.Exists(r.fullPath)) { try { if (!watchers.ContainsKey(r.fullPath)) { watchers[r.fullPath] = new System.IO.FileSystemWatcher(r.fullPath); watchers[r.fullPath].Changed += partialUpdate; watchers[r.fullPath].Created += partialUpdate; watchers[r.fullPath].Deleted += partialUpdate; watchers[r.fullPath].Renamed += partialUpdate; watchers[r.fullPath].IncludeSubdirectories = true; watchers[r.fullPath].EnableRaisingEvents = true; } } catch (NotImplementedException) { //probably on mono, do nothing } } } } } quitComplete = true; quitSemaphore.Release(); isUpdating = false; SystemLog.addEntry("Share update complete."); if (updateComplete != null) { updateComplete(); } }
async Task mapPorts(int internalPort, int externalPort, bool tcp) { try { if (device == null) { initUPnP(); } externalIPFromUPnP = await device.GetExternalIPAsync(); SystemLog.addEntry("Successfully found UPnP device " + await device.GetExternalIPAsync()); Mapping m = new Mapping(tcp ? Protocol.Tcp : Protocol.Udp, internalPort, externalPort, Environment.MachineName + " Dimension Mapping"); await device.CreatePortMapAsync(m); SystemLog.addEntry("Successfully created UPnP mapping from port " + internalPort.ToString() + " to " + externalPort.ToString()); UPnPActive = true; } catch { UPnPActive = false; //UPnP probably not supported } }
public void createConnection(MessageResponseDelegate response = null) { bool createData = true; if (dataConnection != null) { if (dataConnection.connected) { createData = false; } } bool createControl = true; if (controlConnection != null) { if (controlConnection.connected) { createControl = false; } } if (createControl == false && createData == false) { return; } if (id == App.theCore.id) { response?.Invoke("Loopback peer found, creating loopback connection..."); if (createControl) { controlConnection = new LoopbackOutgoingConnection(); } if (createData) { dataConnection = new LoopbackOutgoingConnection(); } } else { if (isLocal && internalAddress != null) { response?.Invoke("Local peer found."); if (internalAddress.Length > 1) { response?.Invoke("Multiple local addresses found. Trying each..."); } for (int i = 0; i < internalAddress.Length; i++) { actualEndpoint = new System.Net.IPEndPoint(internalAddress[i], localControlPort); bool reverseConnect = false; if (App.settings.getBool("Default to Reverse Connection", false)) { reverseConnect = true; } bool rendezvousConnect = false; if (App.settings.getBool("Always Rendezvous", false) && useUDT) { reverseConnect = false; rendezvousConnect = true; } if (!reverseConnect && !rendezvousConnect) { try { if (createControl && controlConnection == null) { response?.Invoke("Creating TCP connection to " + actualEndpoint.Address.ToString() + ":" + localDataPort.ToString()); controlConnection = new ReliableOutgoingConnection(actualEndpoint.Address, localDataPort); } if (createData && dataConnection == null) { response?.Invoke("Creating TCP connection to " + actualEndpoint.Address.ToString() + ":" + localDataPort.ToString()); dataConnection = new ReliableOutgoingConnection(actualEndpoint.Address, localDataPort); } } catch (Exception e) { SystemLog.addEntry("Failed to connect to " + actualEndpoint.Address.ToString()); reverseConnect = true; } } if (reverseConnect) { doReverseConnection(response); return; } if (rendezvousConnect) { doRendezvous(response); return; } } } else { bool reverseConnect = false; if (App.settings.getBool("Default to Reverse Connection", false)) { reverseConnect = true; } bool rendezvousConnect = false; if (App.settings.getBool("Always Rendezvous", false) && useUDT) { reverseConnect = false; rendezvousConnect = true; } if (!reverseConnect && !rendezvousConnect) { try { if (createControl) { response?.Invoke("Creating TCP connection to " + actualEndpoint.Address.ToString() + ":" + externalDataPort.ToString()); controlConnection = new ReliableOutgoingConnection(actualEndpoint.Address, externalDataPort); } if (createData) { response?.Invoke("Creating TCP connection to " + actualEndpoint.Address.ToString() + ":" + externalDataPort.ToString()); dataConnection = new ReliableOutgoingConnection(actualEndpoint.Address, externalDataPort); } } catch (System.Net.Sockets.SocketException s) { response?.Invoke("Error: " + s.Message + "."); reverseConnect = true; } } if (reverseConnect) { doReverseConnection(response); return; } if (rendezvousConnect) { doRendezvous(response); return; } } } if (createData) { if (dataConnection != null && dataConnection != controlConnection) { dataConnection.commandReceived += commandReceived; } } if (createControl && controlConnection != null) { controlConnection.commandReceived += commandReceived; } System.Threading.Thread.Sleep(500); }
public override void Write(string message) { SystemLog.addEntry(message); }
public async Task launch() { SystemLog.addEntry("Beginning network setup..."); SystemLog.addEntry("Deleting old UPnP mappings..."); if (App.settings.getBool("Use UPnP", true)) { bool done = false; System.Threading.Semaphore s = new System.Threading.Semaphore(0, 1); System.Threading.Thread t = new System.Threading.Thread(async delegate() { await unMapPorts(); done = true; s.Release(); }); t.IsBackground = true; t.Name = "UPnP test thread"; t.Start(); if (!done) { s.WaitOne(10000); } if (!done) { SystemLog.addEntry("Failed to find UPnP router in a timely fashion. Disabling UPnP..."); UPnPActive = false; } } SystemLog.addEntry("Binding UDP sockets."); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); listener = new TcpListener(IPAddress.Any, App.settings.getInt("Default Data Port", 0)); listener.Start(); internalDataPort = ((IPEndPoint)listener.Server.LocalEndPoint).Port; SystemLog.addEntry("Binding to TCP port " + internalDataPort.ToString()); int control = App.settings.getInt("Default Control Port", 0); if (control == Dimension.Model.NetConstants.controlPort) { control = 0; } unreliableClient = new UdpClient(control); internalControlPort = ((IPEndPoint)unreliableClient.Client.LocalEndPoint).Port; if (control == 0) { App.settings.setInt("Default Control Port", internalControlPort); } SystemLog.addEntry("Successfully bound to UDP control port " + internalControlPort); publicControlEndPoint = (IPEndPoint)unreliableClient.Client.LocalEndPoint; publicDataEndPoint = (IPEndPoint)listener.Server.LocalEndPoint; tryAgain: if (App.settings.getBool("Use UPnP", true) == false || LANMode || !UPnPActive || behindDoubleNAT) { SystemLog.addEntry("STUNning NAT"); try { string stunUrl = "stun.l.google.com"; STUN_Result result = STUN_Client.Query(stunUrl, 19302, unreliableClient.Client); SystemLog.addEntry("Attempting to STUN control port to " + stunUrl + "."); if (result.NetType == STUN_NetType.UdpBlocked) { SystemLog.addEntry("STUN failed. Assuming network is LAN-only."); LANMode = true; UPnPActive = false; } else { publicControlEndPoint = new IPEndPoint(result.PublicEndPoint.Address, result.PublicEndPoint.Port); publicDataEndPoint = new IPEndPoint(result.PublicEndPoint.Address, internalDataPort); SystemLog.addEntry("STUN successful. External control endpoint: " + result.PublicEndPoint.ToString()); SystemLog.addEntry("External data endpoint: " + publicDataEndPoint.ToString()); } } catch (Exception) //STUN can throw generic exceptions :( { SystemLog.addEntry("Failed to STUN. Working in LAN mode."); //Stun failed, offline mode LANMode = true; } } Random r = new Random(); internalDHTPort = App.settings.getInt("Default DHT Port", 0); if (internalDHTPort == 0) { internalDHTPort = r.Next(short.MaxValue - 1000) + 1000; } publicDHTPort = internalDHTPort; if (App.settings.getBool("Use UPnP", true) && !LANMode && UPnPActive && !behindDoubleNAT) { SystemLog.addEntry("UPnP enabled. Attempting to map UPnP ports..."); publicControlEndPoint = new IPEndPoint(publicControlEndPoint.Address, r.Next(short.MaxValue - 1000) + 1000); publicDataEndPoint = new IPEndPoint(publicControlEndPoint.Address, r.Next(short.MaxValue - 1000) + 1000); publicDHTPort = r.Next(short.MaxValue - 1000) + 1000; SystemLog.addEntry("Creating control UPnP mapping (random external port)..."); await mapPorts(((IPEndPoint)unreliableClient.Client.LocalEndPoint).Port, publicControlEndPoint.Port, false); SystemLog.addEntry("Creating data UPnP mapping (random external port)..."); await mapPorts(((IPEndPoint)listener.Server.LocalEndPoint).Port, publicDataEndPoint.Port, true); SystemLog.addEntry("Creating DHT UPnP mapping (random external port)..."); await mapPorts(internalDHTPort, publicDHTPort, false); publicControlEndPoint = new IPEndPoint(externalIPFromUPnP, publicControlEndPoint.Port); publicDataEndPoint = new IPEndPoint(externalIPFromUPnP, publicDataEndPoint.Port); if (externalIPFromUPnP.ToString().StartsWith("10.") || externalIPFromUPnP.ToString().StartsWith("192.")) { behindDoubleNAT = true; SystemLog.addEntry("WARNING! Your router provided a local IP address as the external endpoint."); SystemLog.addEntry("This probably means you're running more than one router in a row (double NAT)."); SystemLog.addEntry("Dimension is going to disable UPnP and try STUNning again to get through this."); SystemLog.addEntry("If this is your home network, please talk to a network engineer -- having UPnP with double NAT is a very bad idea."); goto tryAgain; } } SystemLog.addEntry("Network setup complete."); }
void updateRootShare(RootShare f, bool urgent) { lock (toSave) toSave.Clear(); if (quitting) { return; } f.id = App.fileListDatabase.allocateId(); ulong size = 0; SystemLog.addEntry("Updating root share " + f.fullPath.Replace('/', System.IO.Path.DirectorySeparatorChar) + "..."); sw = new System.Diagnostics.Stopwatch(); sw.Start(); string path = ""; path = f.fullPath; bool invalidated = false; System.IO.DirectoryInfo d = new System.IO.DirectoryInfo(path); if (d.LastWriteTimeUtc.Ticks != f.lastModified) { invalidated = true; } string s = ""; try { if (d.GetFiles().Length + d.GetDirectories().Length != f.folderIds.Length + f.fileIds.Length) { invalidated = true; } foreach (System.IO.FileInfo i in d.GetFiles()) { s += i.Name + "|" + i.Length.ToString() + "|" + i.LastWriteTimeUtc.Ticks.ToString() + Environment.NewLine; wait(urgent); } foreach (System.IO.DirectoryInfo i in d.GetDirectories()) { s += i.Name + "|" + i.LastWriteTimeUtc.Ticks.ToString() + Environment.NewLine; wait(urgent); } } catch (System.IO.IOException) { return; } string s2 = ""; foreach (ulong id in f.fileIds) { File i = App.fileListDatabase.getObject <File>(App.fileListDatabase.fileList, "FSListing " + id.ToString()); if (i != null) { size += i.size; s2 += i.name + "|" + i.size + "|" + i.lastModified.ToString() + Environment.NewLine; } wait(urgent); } foreach (ulong id in f.folderIds) { Folder i = App.fileListDatabase.getObject <Folder>(App.fileListDatabase.fileList, "FSListing " + id.ToString()); if (i != null) { size += i.size; s2 += i.name + "|" + i.lastModified.ToString() + Environment.NewLine; } wait(urgent); } if (s != s2) { invalidated = true; } if (invalidated) { deleteFolder(f, urgent); size = loadFolder(f, urgent, path); f.size = size; lock (toSave) toSave["FSListing " + f.id] = f; if (!quitting) { App.fileListDatabase.setObject(App.settings.settings, "Root Share " + f.index.ToString(), f); doSave(); } } sw.Stop(); sw.Reset(); }