From 4b2402f80175a8fb3ff8b2bd2e78053211f2e5d5 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Tue, 26 Mar 2019 03:30:55 +0300 Subject: [PATCH] v0.3.2: Speed issue fixed for TF NET installations. Progress bar 'works' for NET installations. Progress bar behavior changed for USB installations. Simplified (simpler code for decorations -> a bit faster files installations). Minor changes to TF side. --- README.md | 6 +- pom.xml | 2 +- .../nsusbloader/NET/NETCommunications.java | 138 +++++++++++++----- src/main/java/nsusbloader/NSLMain.java | 2 +- .../nsusbloader/USB/UsbCommunications.java | 81 +++++----- 5 files changed, 144 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 1f7b58b..78e64c2 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Set 'Security & Privacy' settings if needed. * Click 'Options' and select 'List All Devices' * Select NS in dropdown, select 'libusbK (v3.0.7.0)' (version may vary), click 'Install WCID Driver' * Check that in device list of you system you have 'libusbK USB Devices' folder and your NS inside of it -* Download and install Java JRE (8+) +* Download and install Java JRE (8u60 or higher) * Get this application (JAR file) double-click on on it (alternatively open 'cmd', go to place where jar located and execute via `java -jar thisAppName.jar`) * Remember to have fun! @@ -71,7 +71,9 @@ There you can select checkbox for files that will be send to application (TF/GL) ##### Second tab. -Here you can configure settings for network file transmission. Usually you shouldn't change anything. But it you're cool hacker, go ahead! The most interesting option here is 'Don't serve requests'. Architecture of the TinFoil networking is working interesting way. When you select in TF network NSP transfer, application will wait at port 2000 for the information about where should it take files from. Like '192.168.1.5:6060/my_file.nsp'. Usually NS-USBloader serves requests by implementing simplified HTTP server and bringing it up and so on. But if this option selected, you can define path to remote location of the files. For example if you set in settings 'shared.lan:80/ROMS/NS/' and add in table file 'my file.nsp' then NS-USBloader will simply tell TinFoil "Hey, go take files from 'shared.lan:80/ROMS/NS/my+file.nsp' ". Of course you have to bring 'shared.lan' host up and make file accessible from such address. All this requires more investigation. BTW, the issue could be that NS-USBloader encodes 'space' char as '+' and some web-servers understand 'space' as '%20D'. It could be fixed in later versions of NS-USBloader if I go deeper in it or you leave me feedback with information/request. As I said, this feature is interesting, but I guess won't be popular. +Here you can configure settings for network file transmission. Usually you shouldn't change anything. But it you're cool hacker, go ahead! The most interesting option here is 'Don't serve requests'. Architecture of the TinFoil's NET part is working interesting way. When you select in TF network NSP transfer, application will wait at port 2000 for the information about where should it take files from. Like '192.168.1.5:6060/my file.nsp'. Usually NS-USBloader serves requests by implementing simplified HTTP server and bringing it up and so on. But if this option selected, you can define path to remote location of the files. For example if you set in settings '192.168.4.2:80/ROMS/NS/' and add in table file 'my file.nsp' then NS-USBloader will simply tell TinFoil "Hey, go take files from '192.168.4.2:80/ROMS/NS/my%20file.nsp' ". Of course you have to bring '192.168.4.2' host up and make file accessible from such address (just go install nginx). As I said, this feature is interesting, but I guess won't be popular. + +Also here you can check 'Auto-check for updates' or click button to verify if new version released or not. ##### Third tab. diff --git a/pom.xml b/pom.xml index 8cd9b25..2b9d911 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ NS-USBloader ns-usbloader - 0.3.1-SNAPSHOT + 0.3.2-SNAPSHOT https://github.com/developersu/ns-usbloader/ diff --git a/src/main/java/nsusbloader/NET/NETCommunications.java b/src/main/java/nsusbloader/NET/NETCommunications.java index 0ac6596..52997eb 100644 --- a/src/main/java/nsusbloader/NET/NETCommunications.java +++ b/src/main/java/nsusbloader/NET/NETCommunications.java @@ -45,7 +45,7 @@ public class NETCommunications extends Task { // todo: thows IOException? // Collect and encode NSP files list try { for (File nspFile : filesList) - nspMap.put(URLEncoder.encode(nspFile.getName(), "UTF-8"), nspFile); + nspMap.put(URLEncoder.encode(nspFile.getName(), "UTF-8").replaceAll("\\+", "%20"), nspFile); // replace + to %20 } catch (UnsupportedEncodingException uee){ isValid = false; @@ -63,21 +63,24 @@ public class NETCommunications extends Task { // todo: thows IOException? socket.connect(InetAddress.getByName("8.8.8.8"), 10002); // Google hostIP = socket.getLocalAddress().getHostAddress(); socket.close(); - } catch (SocketException | UnknownHostException e) { + } + catch (SocketException | UnknownHostException e) { logPrinter.print("NET: Can't get your computer IP using Google DNS server. Returned:\n\t"+e.getMessage(), EMsgType.INFO); try { socket = new DatagramSocket(); socket.connect(InetAddress.getByName("193.0.14.129"), 10002); // RIPE NCC hostIP = socket.getLocalAddress().getHostAddress(); socket.close(); - } catch (SocketException | UnknownHostException e1) { + } + catch (SocketException | UnknownHostException e1) { logPrinter.print("NET: Can't get your computer IP using RIPE NCC root server. Returned:\n\t"+e1.getMessage(), EMsgType.INFO); try { socket = new DatagramSocket(); socket.connect(InetAddress.getByName("people.com.cn"), 10002); // Renmin Ribao hostIP = socket.getLocalAddress().getHostAddress(); socket.close(); - } catch (SocketException | UnknownHostException e2) { + } + catch (SocketException | UnknownHostException e2) { logPrinter.print("NET: Can't get your computer IP using Renmin Ribao server. Returned:\n\t"+e2.getMessage(), EMsgType.FAIL); logPrinter.print("Try using 'Expert mode' and set IP manually.", EMsgType.INFO); try { @@ -90,7 +93,8 @@ public class NETCommunications extends Task { // todo: thows IOException? logPrinter.print("Check for: " + i.getHostAddress(), EMsgType.INFO); } } - } catch (SocketException socketException) { // Good block. + } + catch (SocketException socketException) { // Good block. logPrinter.print("Can't determine possible variants. Returned:\n\t"+socketException.getMessage(), EMsgType.FAIL); } isValid = false; @@ -107,33 +111,58 @@ public class NETCommunications extends Task { // todo: thows IOException? } // Get port - if (hostPortNum.isEmpty()) { - Random portRandomizer = new Random(); - for (int i = 0; i < 5; i++) { + if (! doNotServeRequests) { + if (hostPortNum.isEmpty()) { + Random portRandomizer = new Random(); + for (int i = 0; i < 5; i++) { + try { + this.hostPort = portRandomizer.nextInt(999) + 6000; + serverSocket = new ServerSocket(hostPort); //System.out.println(serverSocket.getInetAddress()); 0.0.0.0 + logPrinter.print("NET: Your port detected as: " + hostPort, EMsgType.PASS); + break; + } + catch (IOException ioe) { + if (i == 4) { + logPrinter.print("NET: Can't find good port", EMsgType.FAIL); + logPrinter.print("Try using 'Expert mode' and set port by yourself.", EMsgType.INFO); + isValid = false; + close(EFileStatus.FAILED); + return; + } else + logPrinter.print("NET: Can't use port " + hostPort + "\nLooking for another one.", EMsgType.WARNING); + } + } + } else { try { - this.hostPort = portRandomizer.nextInt(999) + 6000; - serverSocket = new ServerSocket(hostPort); //System.out.println(serverSocket.getInetAddress()); 0.0.0.0 - logPrinter.print("NET: Your port detected as: " + hostPort, EMsgType.PASS); - break; - } catch (IOException ioe) { - if (i == 4) { - logPrinter.print("NET: Can't find good port", EMsgType.FAIL); - logPrinter.print("Try using 'Expert mode' and set port by yourself.", EMsgType.INFO); - isValid = false; - close(EFileStatus.FAILED); - return; - } else - logPrinter.print("NET: Can't use port " + hostPort + "\nLooking for another one.", EMsgType.WARNING); + this.hostPort = Integer.parseInt(hostPortNum); + serverSocket = new ServerSocket(hostPort); + logPrinter.print("NET: Using defined port number: " + hostPort, EMsgType.PASS); + } + catch (NumberFormatException nfe) { // Literally never happens. + logPrinter.print("NET: Can't use port defined in settings: " + hostPortNum + "\nIt's not a valid number!", EMsgType.FAIL); + isValid = false; + close(EFileStatus.FAILED); + return; + } + catch (IOException ioex){ + logPrinter.print("NET: Can't use port defined in settings: " + hostPortNum + "\n\t"+ioex.getMessage(), EMsgType.FAIL); + isValid = false; + close(EFileStatus.FAILED); + return; } } } else { - try { - this.hostPort = Integer.parseInt(hostPortNum); - serverSocket = new ServerSocket(hostPort); - logPrinter.print("NET: Using defined port number: " + hostPort, EMsgType.PASS); + if (hostPortNum.isEmpty()){ + logPrinter.print("NET: Port must be defined if 'Don't serve requests' option selected!", EMsgType.FAIL); + isValid = false; + close(EFileStatus.FAILED); + return; } - catch (NumberFormatException | IOException exeption){ // Literally never happens. + try { + this.hostPort = Integer.parseInt(hostPortNum); + } + catch (NumberFormatException fex){ logPrinter.print("NET: Can't use port defined in settings: " + hostPortNum + "\nIt's not a valid number!", EMsgType.WARNING); isValid = false; close(EFileStatus.FAILED); @@ -315,17 +344,54 @@ public class NETCommunications extends Task { // todo: thows IOException? * Send files. * */ private boolean writeToSocket(File file, long start, long end){ + logPrinter.print("NET: Responding to requested range: "+start+"-"+end, EMsgType.INFO); currSockPW.write(NETPacket.getCode206(file.length(), start, end)); currSockPW.flush(); try{ - long count = end - start; + long count = end - start + 1; - RandomAccessFile raf = new RandomAccessFile(file, "r"); - raf.seek(start); - for (int i=0; i <= count; i++) - currSockOS.write(raf.read()); - currSockOS.flush(); - raf.close(); + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + int readPice = 8388608; // = 8Mb + byte[] byteBuf; + + if (bis.skip(start) != start){ + logPrinter.print("NET: Unable to skip requested range.", EMsgType.FAIL); + logPrinter.update(file, EFileStatus.FAILED); + return true; + } + long currentOffset = 0; + while (currentOffset < count){ + if (isCancelled()) + return true; + if ((currentOffset+readPice) >= count){ + readPice = Math.toIntExact(count - currentOffset); + } + byteBuf = new byte[readPice]; + + if (bis.read(byteBuf) != readPice){ + logPrinter.print("NET: Reading of file stream suddenly ended.", EMsgType.FAIL); + return true; + } + currSockOS.write(byteBuf); + //-----------------------------------------/ + try { + logPrinter.updateProgress((currentOffset+readPice)/(count/100.0) / 100.0); + }catch (InterruptedException ie){ + getException().printStackTrace(); // TODO: Do something with this + } + //-----------------------------------------/ + currentOffset += readPice; + } + currSockOS.flush(); // TODO: check if this really needed. + bis.close(); + //-----------------------------------------/ + try{ + logPrinter.updateProgress(1.0); + } + catch (InterruptedException ie){ + getException().printStackTrace(); // TODO: Do something with this + } + //-----------------------------------------/ } catch (IOException ioe){ logPrinter.print("NET: File transmission failed. Returned:\n\t"+ioe.getMessage(), EMsgType.FAIL); @@ -341,8 +407,10 @@ public class NETCommunications extends Task { // todo: thows IOException? if (isCancelled()) logPrinter.print("NET: Interrupted by user.", EMsgType.INFO); try { - serverSocket.close(); - logPrinter.print("NET: Closing server socket.", EMsgType.PASS); + if (serverSocket != null) { + serverSocket.close(); + logPrinter.print("NET: Closing server socket.", EMsgType.PASS); + } } catch (IOException | NullPointerException ioe){ logPrinter.print("NET: Closing server socket failed. Sometimes it's not an issue.", EMsgType.WARNING); diff --git a/src/main/java/nsusbloader/NSLMain.java b/src/main/java/nsusbloader/NSLMain.java index 47eb5be..a531368 100644 --- a/src/main/java/nsusbloader/NSLMain.java +++ b/src/main/java/nsusbloader/NSLMain.java @@ -12,7 +12,7 @@ import java.util.Locale; import java.util.ResourceBundle; public class NSLMain extends Application { - public static final String appVersion = "v0.3.1"; + public static final String appVersion = "v0.3.2"; @Override public void start(Stage primaryStage) throws Exception{ diff --git a/src/main/java/nsusbloader/USB/UsbCommunications.java b/src/main/java/nsusbloader/USB/UsbCommunications.java index 660fe02..9eafbec 100644 --- a/src/main/java/nsusbloader/USB/UsbCommunications.java +++ b/src/main/java/nsusbloader/USB/UsbCommunications.java @@ -359,7 +359,7 @@ public class UsbCommunications extends Task { BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(nspMap.get(receivedRequestedNSP))); // TODO: refactor? byte[] bufferCurrent ;//= new byte[1048576]; // eq. Allocate 1mb - int bufferLength; + if (bufferedInStream.skip(receivedRangeOffset) != receivedRangeOffset){ logPrinter.print("TF Requested skip is out of file size. Nothing to transmit.", EMsgType.FAIL); return false; @@ -376,43 +376,35 @@ public class UsbCommunications extends Task { readPice = Math.toIntExact(receivedRangeSize - currentOffset); //System.out.println("CO: "+currentOffset+"\t\tEO: "+receivedRangeSize+"\t\tRP: "+readPice); // TODO: NOTE: DEBUG // updating progress bar (if a lot of data requested) START BLOCK - if (isProgessBarInitiated){ - try { - if (currentOffset+readPice == receivedRangeOffset){ - logPrinter.updateProgress(1.0); - isProgessBarInitiated = false; - } - else - logPrinter.updateProgress((currentOffset+readPice)/(receivedRangeSize/100.0) / 100.0); - }catch (InterruptedException ie){ - getException().printStackTrace(); // TODO: Do something with this - } + //-----------------------------------------/ + try { + logPrinter.updateProgress((currentOffset+readPice)/(receivedRangeSize/100.0) / 100.0); + }catch (InterruptedException ie){ + getException().printStackTrace(); // TODO: Do something with this } - else { - if ((readPice == 8388608) && (currentOffset == 0)) - isProgessBarInitiated = true; - } - // updating progress bar if needed END BLOCK - + //-----------------------------------------/ bufferCurrent = new byte[readPice]; // TODO: not perfect moment, consider refactoring. - bufferLength = bufferedInStream.read(bufferCurrent); - - if (bufferLength != -1){ - //write to USB - if (!writeToUsb(bufferCurrent)) { - logPrinter.print("TF Failure during NSP transmission.", EMsgType.FAIL); - return false; - } - currentOffset += readPice; - } - else { + if (bufferedInStream.read(bufferCurrent) != readPice) { // changed since @ v0.3.2 logPrinter.print("TF Reading of stream suddenly ended.", EMsgType.WARNING); return false; } - + //write to USB + if (!writeToUsb(bufferCurrent)) { + logPrinter.print("TF Failure during NSP transmission.", EMsgType.FAIL); + return false; + } + currentOffset += readPice; } bufferedInStream.close(); + //-----------------------------------------/ + try{ + logPrinter.updateProgress(1.0); + } + catch (InterruptedException ie){ + getException().printStackTrace(); // TODO: Do something with this + } + //-----------------------------------------/ } catch (FileNotFoundException fnfe){ logPrinter.print("TF FileNotFoundException:\n "+fnfe.getMessage(), EMsgType.FAIL); fnfe.printStackTrace(); @@ -422,7 +414,7 @@ public class UsbCommunications extends Task { ioe.printStackTrace(); return false; } catch (ArithmeticException ae){ - logPrinter.print("TF ArithmeticException (can't cast end offset minus current to 'integer'):\n "+ae.getMessage(), EMsgType.FAIL); + logPrinter.print("TF ArithmeticException (can't cast 'offset end' - 'offsets current' to 'integer'):\n "+ae.getMessage(), EMsgType.FAIL); ae.printStackTrace(); return false; } @@ -653,26 +645,23 @@ public class UsbCommunications extends Task { if (!writeToUsb(readBuf)) return false; //-----------------------------------------/ - if (isProgessBarInitiated){ - try { - if (readFrom+readPice == realNcaSize){ - logPrinter.updateProgress(1.0); - isProgessBarInitiated = false; - } - else - logPrinter.updateProgress((readFrom+readPice)/(realNcaSize/100.0) / 100.0); - }catch (InterruptedException ie){ - getException().printStackTrace(); // TODO: Do something with this - } - } - else { - if ((readPice == 8388608) && (readFrom == 0)) - isProgessBarInitiated = true; + try { + logPrinter.updateProgress((readFrom+readPice)/(realNcaSize/100.0) / 100.0); + }catch (InterruptedException ie){ + getException().printStackTrace(); // TODO: Do something with this } //-----------------------------------------/ readFrom += readPice; } bufferedInStream.close(); + //-----------------------------------------/ + try{ + logPrinter.updateProgress(1.0); + } + catch (InterruptedException ie){ + getException().printStackTrace(); // TODO: Do something with this + } + //-----------------------------------------/ } catch (IOException ioe){ logPrinter.print(" Failed to read NCA ID "+requestedNcaID+". IO Exception:\n "+ioe.getMessage(), EMsgType.FAIL);