├── .gitattributes ├── .gitignore ├── child.svg ├── error.svg ├── extend-child.svg ├── fGetIPAddresses.js ├── fXHRScanIPAddressPorts.js ├── fxIPAddress.js ├── index.html ├── info.svg ├── last-child.svg ├── machine.svg ├── network.svg ├── nix.svg ├── scanning.svg ├── unknown.svg └── windows.svg /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /child.svg: -------------------------------------------------------------------------------- 1 | 5 | 11 | -------------------------------------------------------------------------------- /error.svg: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /extend-child.svg: -------------------------------------------------------------------------------- 1 | 5 | 11 | -------------------------------------------------------------------------------- /fGetIPAddresses.js: -------------------------------------------------------------------------------- 1 | function fGetIPAddresses(oIFrame, fSuccessCallback, fErrorCallback) { 2 | // 3 | function fcGetRTCPeerConnection(oWindow) { 4 | return oWindow && (oWindow.RTCPeerConnection || oWindow.mozRTCPeerConnection || oWindow.webkitRTCPeerConnection); 5 | } 6 | var cRTCPeerConnection = fcGetRTCPeerConnection(window) || fcGetRTCPeerConnection(oIFrame.contentWindow); 7 | if (!cRTCPeerConnection) { 8 | fErrorCallback("RTCPeerConnection feature not available"); 9 | return; 10 | }; 11 | 12 | var oRTCPeerConnection = new cRTCPeerConnection( 13 | { "iceServers": [ 14 | { "urls": "stun:stun.services.mozilla.com" }, 15 | ] }, 16 | { "optional": [ 17 | { "RtpDataChannels": true }, 18 | ] } 19 | ); 20 | 21 | dsIPAddresses = {}; 22 | oRTCPeerConnection.onicecandidate = function fRTCPeerConnectionIceEventHandler(oRTCPeerConnectionIceEvent){ 23 | var oRTCIceCandidate = oRTCPeerConnectionIceEvent.candidate; 24 | if (oRTCIceCandidate) { 25 | var asCandidate = oRTCIceCandidate.candidate.split(" "); 26 | if (asCandidate[7] == "host") { 27 | var sIPAddress = asCandidate[4]; 28 | if (/[0-9]{1,3}(?:\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7}/.exec(sIPAddress)) { 29 | dsIPAddresses[sIPAddress] = 1; 30 | } else { 31 | console.log("Ignored RTCIceCandidate " + JSON.stringify(oRTCIceCandidate.candidate) + ": not an IP address."); 32 | }; 33 | } else { 34 | console.log("Ignored RTCIceCandidate " + JSON.stringify(oRTCIceCandidate.candidate) + ": not a \"host\"."); 35 | }; 36 | } else { 37 | fSuccessCallback(Object.keys(dsIPAddresses)); 38 | }; 39 | }; 40 | 41 | oRTCPeerConnection.createDataChannel(""); 42 | oRTCPeerConnection.createOffer( 43 | function fCreateOfferSuccess(oRTCSessionDescription){ 44 | oRTCPeerConnection.setLocalDescription( 45 | oRTCSessionDescription, 46 | function fSetLocalDescriptionSuccess(){ 47 | }, 48 | function fSetLocalDescriptionError(sErrorMessage){ 49 | fErrorCallback("Could not set local description: " + sErrorMessage); 50 | } 51 | ); 52 | }, 53 | function fCreateOfferError(sErrorMessage){ 54 | fErrorCallback("Could not create offer: " + sErrorMessage); 55 | } 56 | ); 57 | }; 58 | -------------------------------------------------------------------------------- /fXHRScanIPAddressPorts.js: -------------------------------------------------------------------------------- 1 | function fXHRScanIPAddressPorts(sIPAddress, auPortNumbers, fCallback) { 2 | var auDetectedPorts = []; 3 | (function fLoop() { 4 | if (auPortNumbers.length) { 5 | var uPortNumber = auPortNumbers.pop(), 6 | oXHR = new XMLHttpRequest(), 7 | bFinished = false, 8 | oTimeout = setTimeout(function fXHRTimeout() { 9 | if (!bFinished) { 10 | bFinished = true; 11 | oXHR.abort(); 12 | fLoop(); 13 | }; 14 | }, 1500); 15 | oXHR.onreadystatechange = function fXHRReadyStateChangeEventHandler(oEvent) { 16 | if (oXHR.readyState == 4 && !bFinished) { 17 | bFinished = true; 18 | clearTimeout(oTimeout); 19 | auDetectedPorts.push(uPortNumber); 20 | fLoop(); 21 | }; 22 | }; 23 | oXHR.open("GET", location.protocol + "//" + sIPAddress + ":" + uPortNumber); 24 | oXHR.send(); 25 | } else { 26 | console.log("IP: " + sIPAddress + ", ports: " + (auDetectedPorts.join(", ") || "none")); 27 | fCallback(auDetectedPorts); 28 | }; 29 | })(); 30 | }; -------------------------------------------------------------------------------- /fxIPAddress.js: -------------------------------------------------------------------------------- 1 | function fuIPAddress(sIPAddress) { 2 | var asComponents = /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/.exec(sIPAddress); 3 | if (!asComponents) throw new TypeError("Invalid IPv4 address " + sIPAddress); 4 | var uIPAddress = 0; 5 | for (var uByte = 0; uByte < 4; uByte++) { 6 | uIPAddress = (uIPAddress << 8) + parseInt(asComponents[uByte + 1]); // no sanity checks! 7 | }; 8 | return uIPAddress; 9 | }; 10 | 11 | function fsIPAddress(uIPAddress) { 12 | var asIPAddress = []; 13 | for (var uByte = 0; uByte < 4; uByte++) { 14 | asIPAddress[uByte] = ((uIPAddress >> (24 - uByte * 8)) & 0xFF).toString(); 15 | }; 16 | return asIPAddress.join("."); 17 | }; 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 28 | 29 | 30 | 31 | 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /info.svg: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /last-child.svg: -------------------------------------------------------------------------------- 1 | 5 | 11 | -------------------------------------------------------------------------------- /machine.svg: -------------------------------------------------------------------------------- 1 | 5 | 7 | -------------------------------------------------------------------------------- /network.svg: -------------------------------------------------------------------------------- 1 | 5 | 11 | -------------------------------------------------------------------------------- /nix.svg: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /scanning.svg: -------------------------------------------------------------------------------- 1 | 5 | 10 | 14 | 23 | 24 | -------------------------------------------------------------------------------- /unknown.svg: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /windows.svg: -------------------------------------------------------------------------------- 1 | 5 | 9 | --------------------------------------------------------------------------------