I woke up this morning and thought that I may commit anything without good reason.
So that's what I'm doing.
This commit is contained in:
		
							parent
							
								
									d55e1c9ba9
								
							
						
					
					
						commit
						9bf4a76076
					
				
					 8 changed files with 191 additions and 46 deletions
				
			
		|  | @ -88,7 +88,7 @@ Français by [Stephane Meden (JackFromNice)](https://github.com/JackFromNice) | |||
| - [ ] XCI support | ||||
| - [ ] File order sort (non-critical) | ||||
| - [ ] More deep file analyze before uploading. | ||||
| - [] Network mode support for TinFoil | ||||
| - [x] Network mode support for TinFoil | ||||
| 
 | ||||
| ## Thanks | ||||
| Appreciate assistance and support of both Vitaliy and Konstantin. Without you all this magic would not have happened. | ||||
|  |  | |||
|  | @ -13,12 +13,16 @@ import javafx.stage.FileChooser; | |||
| import nsusbloader.AppPreferences; | ||||
| import nsusbloader.MediatorControl; | ||||
| import nsusbloader.NET.NETCommunications; | ||||
| import nsusbloader.NET.NETPacket; | ||||
| import nsusbloader.NSLMain; | ||||
| import nsusbloader.ServiceWindow; | ||||
| import nsusbloader.USB.UsbCommunications; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.net.URL; | ||||
| import java.time.LocalDateTime; | ||||
| import java.time.ZoneOffset; | ||||
| import java.time.format.DateTimeFormatter; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.ResourceBundle; | ||||
|  | @ -47,14 +51,14 @@ public class NSLMainController implements Initializable { | |||
|     @FXML | ||||
|     public NSTableViewController tableFilesListController;            // Accessible from Mediator | ||||
|     @FXML | ||||
|     private NetTabController NetTabController; | ||||
|     private SettingsController SettingsTabController; | ||||
|     @FXML | ||||
|     private TextField nsIpTextField; | ||||
|     @FXML | ||||
|     private Label nsIpLbl; | ||||
| 
 | ||||
|     private UsbCommunications usbCommunications; | ||||
|     private Thread usbThread; | ||||
|     private Thread workThread; | ||||
| 
 | ||||
|     private String previouslyOpenedPath; | ||||
| 
 | ||||
|  | @ -177,7 +181,7 @@ public class NSLMainController implements Initializable { | |||
|      * It's button listener when no transmission executes | ||||
|      * */ | ||||
|     private void uploadBtnAction(){ | ||||
|         if ((usbThread == null || !usbThread.isAlive())){ | ||||
|         if ((workThread == null || !workThread.isAlive())){ | ||||
|             if (choiceProtocol.getSelectionModel().getSelectedItem().equals("GoldLeaf") || | ||||
|                     ( | ||||
|                     choiceProtocol.getSelectionModel().getSelectedItem().equals("TinFoil") | ||||
|  | @ -188,26 +192,38 @@ public class NSLMainController implements Initializable { | |||
|                 if ((nspToUpload = tableFilesListController.getFilesForUpload()) == null) { | ||||
|                     logArea.setText(resourceBundle.getString("logsNoFolderFileSelected")); | ||||
|                     return; | ||||
|                 }else { | ||||
|                 } | ||||
|                 else { | ||||
|                     logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n"); | ||||
|                     for (File item: nspToUpload) | ||||
|                         logArea.appendText("  "+item.getAbsolutePath()+"\n"); | ||||
|                 } | ||||
|                 usbCommunications = new UsbCommunications(nspToUpload, choiceProtocol.getSelectionModel().getSelectedItem()); | ||||
|                 usbThread = new Thread(usbCommunications); | ||||
|                 usbThread.setDaemon(true); | ||||
|                 usbThread.start(); | ||||
|                 workThread = new Thread(usbCommunications); | ||||
|                 workThread.setDaemon(true); | ||||
|                 workThread.start(); | ||||
|             } | ||||
|             else {      // NET INSTALL OVER TINFOIL | ||||
|                 if (NetTabController.isNsIpValidate() && !nsIpTextField.getText().trim().matches("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$")) | ||||
|                 if (SettingsTabController.isNsIpValidate() && !nsIpTextField.getText().trim().matches("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$")) | ||||
|                     if (!ServiceWindow.getConfirmationWindow(resourceBundle.getString("windowTitleBadIp"),resourceBundle.getString("windowBodyBadIp"))) | ||||
|                         return; | ||||
|                 String nsIP = nsIpTextField.getText().trim(); | ||||
|                 if (!NetTabController.getExpertModeSelected()) { | ||||
|                     NETCommunications netCommunications = new NETCommunications(nsIP); | ||||
|                     usbThread = new Thread(netCommunications); | ||||
|                     usbThread.setDaemon(true); | ||||
|                     usbThread.start(); | ||||
| 
 | ||||
|                 List<File> nspToUpload; | ||||
|                 if (!SettingsTabController.getExpertModeSelected()) { | ||||
|                     if ((nspToUpload = tableFilesListController.getFilesForUpload()) == null) { | ||||
|                         logArea.setText(resourceBundle.getString("logsNoFolderFileSelected")); | ||||
|                         return; | ||||
|                     } | ||||
|                     else { | ||||
|                         logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n"); | ||||
|                         for (File item: nspToUpload) | ||||
|                             logArea.appendText("  "+item.getAbsolutePath()+"\n"); | ||||
|                     } | ||||
|                     NETCommunications netCommunications = new NETCommunications(nspToUpload, nsIP);      // TODO: move somewhere | ||||
|                     workThread = new Thread(netCommunications); | ||||
|                     workThread.setDaemon(true); | ||||
|                     workThread.start(); | ||||
|                 } | ||||
|                 else { | ||||
|                     // TODO; pass to another constructor | ||||
|  | @ -219,8 +235,8 @@ public class NSLMainController implements Initializable { | |||
|      * It's button listener when transmission in progress | ||||
|      * */ | ||||
|     private void stopBtnAction(){ | ||||
|         if (usbThread != null && usbThread.isAlive()){ | ||||
|             usbCommunications.cancel(false); | ||||
|         if (workThread != null && workThread.isAlive()){ | ||||
|             usbCommunications.cancel(false);            // TODO: add something abstract to use also for network | ||||
|         } | ||||
|     } | ||||
|     /** | ||||
|  | @ -303,7 +319,8 @@ public class NSLMainController implements Initializable { | |||
|         AppPreferences.getInstance().setRecent(previouslyOpenedPath); | ||||
|         AppPreferences.getInstance().setNetUsb(choiceNetUsb.getSelectionModel().getSelectedItem()); | ||||
|         AppPreferences.getInstance().setNsIp(nsIpTextField.getText().trim()); | ||||
|         AppPreferences.getInstance().setNsIpValidationNeeded(NetTabController.isNsIpValidate()); | ||||
|         AppPreferences.getInstance().setExpertMode(NetTabController.getExpertModeSelected()); | ||||
| 
 | ||||
|         AppPreferences.getInstance().setNsIpValidationNeeded(SettingsTabController.isNsIpValidate()); | ||||
|         AppPreferences.getInstance().setExpertMode(SettingsTabController.getExpertModeSelected()); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ import nsusbloader.AppPreferences; | |||
| import java.net.URL; | ||||
| import java.util.ResourceBundle; | ||||
| 
 | ||||
| public class NetTabController implements Initializable { | ||||
| public class SettingsController implements Initializable { | ||||
| 
 | ||||
|     @FXML | ||||
|     private CheckBox validateNSHostNameCb; | ||||
|  | @ -25,6 +25,7 @@ public class NetTabController implements Initializable { | |||
|     @Override | ||||
|     public void initialize(URL url, ResourceBundle resourceBundle) { | ||||
|         validateNSHostNameCb.setSelected(AppPreferences.getInstance().getNsIpValidationNeeded()); | ||||
| 
 | ||||
|         if (AppPreferences.getInstance().getExpertMode()) { | ||||
|             expertModeCb.setSelected(true); | ||||
|             hostIpLbl.setVisible(true); | ||||
|  | @ -1,42 +1,109 @@ | |||
| package nsusbloader.NET; | ||||
| 
 | ||||
| import javafx.concurrent.Task; | ||||
| import nsusbloader.NSLMain; | ||||
| 
 | ||||
| import java.io.*; | ||||
| import java.net.*; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.time.LocalDate; | ||||
| import java.time.LocalDateTime; | ||||
| import java.time.format.DateTimeFormatter; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| /* | ||||
| * Add option: don't serve replies | ||||
| * */ | ||||
| 
 | ||||
| public class NETCommunications extends Task<Void> { // todo: thows IOException | ||||
| public class NETCommunications extends Task<Void> { // todo: thows IOException? | ||||
| 
 | ||||
|     private String hostIP; | ||||
|     private int hostPort; | ||||
|     private String switchIP; | ||||
| 
 | ||||
|     private HashMap<String, File> nspMap; | ||||
| 
 | ||||
| 
 | ||||
|     private ServerSocket serverSocket; | ||||
| 
 | ||||
|     public NETCommunications(String switchIP){ | ||||
|     public NETCommunications(List<File> filesList, String switchIP){ | ||||
|         this.switchIP = switchIP; | ||||
|         this.nspMap = new HashMap<>(); | ||||
|         try { | ||||
|             for (File nspFile : filesList) | ||||
|                 nspMap.put(URLEncoder.encode(nspFile.getName(), "UTF-8"), nspFile); | ||||
|         } | ||||
|         catch (UnsupportedEncodingException uee){ | ||||
|             uee.printStackTrace(); | ||||
|             return;                    // TODO: FIX | ||||
|         } | ||||
| 
 | ||||
|         try{        // todo: check other method if internet unavaliable | ||||
|             DatagramSocket socket = new DatagramSocket(); | ||||
|             socket.connect(InetAddress.getByName("8.8.8.8"), 10002);    //193.0.14.129 RIPE NCC | ||||
|             hostIP = socket.getLocalAddress().getHostAddress(); | ||||
|             System.out.println(hostIP); | ||||
|             //System.out.println(hostIP); | ||||
|             socket.close(); | ||||
|         } | ||||
|         catch (SocketException | UnknownHostException e){ | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         this.hostPort = 6000;                         // TODO: fix | ||||
| 
 | ||||
|         try { | ||||
|             serverSocket = new ServerSocket(6000); // TODO: randomize | ||||
| 
 | ||||
|             serverSocket = new ServerSocket(hostPort); // TODO: randomize | ||||
|             //System.out.println(serverSocket.getInetAddress()); 0.0.0.0 | ||||
|         } | ||||
|         catch (IOException ioe){ | ||||
|             ioe.printStackTrace(); | ||||
|             System.out.println("unable to use socket"); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| /* | ||||
| Replace everything to ASCII (WEB representation) | ||||
| calculate | ||||
| write in first 4 bytes | ||||
| * */ | ||||
|     @Override | ||||
|     protected Void call() { | ||||
|         // Get files list length | ||||
|         StringBuilder myStrBuilder; | ||||
| 
 | ||||
|         myStrBuilder = new StringBuilder(); | ||||
|         for (String fileNameEncoded : nspMap.keySet()) { | ||||
|             myStrBuilder.append(hostIP); | ||||
|             myStrBuilder.append(':'); | ||||
|             myStrBuilder.append(hostPort); | ||||
|             myStrBuilder.append('/'); | ||||
|             myStrBuilder.append(fileNameEncoded); | ||||
|             myStrBuilder.append('\n'); | ||||
|         } | ||||
| 
 | ||||
|     @Override | ||||
|     protected Void call() throws Exception { | ||||
| 
 | ||||
|         byte[] nspListNames = myStrBuilder.toString().getBytes(StandardCharsets.UTF_8);                 // Follow the | ||||
|         byte[] nspListSize = ByteBuffer.allocate(Integer.BYTES).putInt(nspListNames.length).array();    // defining order | ||||
| 
 | ||||
|         try { | ||||
|             Socket handShakeSocket = new Socket(InetAddress.getByName(switchIP), 2000); | ||||
|             OutputStream os = handShakeSocket.getOutputStream(); | ||||
| 
 | ||||
|             os.write(nspListSize); | ||||
|             os.write(nspListNames); | ||||
|             os.flush(); | ||||
| 
 | ||||
|             handShakeSocket.close(); | ||||
|         } | ||||
|         catch (IOException uhe){ | ||||
|             uhe.printStackTrace();          // TODO: FIX: could be [UnknownHostException] | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         // Go transfer | ||||
|         try { | ||||
|             Socket clientSocket = serverSocket.accept(); | ||||
| 
 | ||||
|             InputStream is = clientSocket.getInputStream(); | ||||
|  | @ -48,15 +115,39 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException | |||
|             PrintWriter pw = new PrintWriter(osr); | ||||
| 
 | ||||
|             String line; | ||||
|             LinkedList<String> tcpPackeet = new LinkedList<>(); | ||||
|             while ((line = br.readLine()) != null) { | ||||
|             if (line.equals("hello world")) { | ||||
|                 pw.write("stop doing it!"); | ||||
|                 pw.flush(); | ||||
|                 break; | ||||
|                 System.out.println(line);              // TODO: remove DBG | ||||
|                 if (line.trim().isEmpty()) {           // If TCP packet is ended | ||||
|                     handleRequest(tcpPackeet, pw);     // Proceed required things | ||||
|                     tcpPackeet.clear();                // Clear data and wait for next TCP packet | ||||
|                 } | ||||
|             System.out.println(line); | ||||
|                 else | ||||
|                     tcpPackeet.add(line);               // Otherwise collect data | ||||
|             } | ||||
|             System.out.println("\nDone!"); // reopen client sock | ||||
|             clientSocket.close(); | ||||
|             serverSocket.close(); | ||||
|         } | ||||
|         catch (IOException ioe){ | ||||
|             ioe.printStackTrace();          // TODO: fix | ||||
|         } | ||||
| 
 | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     // 200 206 400 (inv range) 404 | ||||
|     private void handleRequest(LinkedList<String> packet, PrintWriter pw){ | ||||
|         if (packet.get(0).startsWith("HEAD")){ | ||||
|             File requestedFile = nspMap.get(packet.get(0).replaceAll("(^[A-z\\s]+/)|(\\s+?.*$)", "")); | ||||
|             if (requestedFile == null || !requestedFile.exists()){ | ||||
|                 return;                     //todo: send 404 | ||||
|             } | ||||
|             else { | ||||
|                 pw.write(NETPacket.getCode200(requestedFile.length())); | ||||
|                 pw.flush(); | ||||
|                 System.out.println(requestedFile.getAbsolutePath()+"\n"+NETPacket.getCode200(requestedFile.length())); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										36
									
								
								src/main/java/nsusbloader/NET/NETPacket.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/main/java/nsusbloader/NET/NETPacket.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| package nsusbloader.NET; | ||||
| 
 | ||||
| import nsusbloader.NSLMain; | ||||
| 
 | ||||
| import java.time.ZoneId; | ||||
| import java.time.ZonedDateTime; | ||||
| import java.time.format.DateTimeFormatter; | ||||
| 
 | ||||
| public class NETPacket { | ||||
|     private static final String CODE_200 = | ||||
|                                             "HTTP/1.0 200 OK\r\n" + | ||||
|                                             "Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" + | ||||
|                                             "Date: %s\r\n" + | ||||
|                                             "Content-type: application/octet-stream\r\n" + | ||||
|                                             "Accept-Ranges: bytes\r\n" + | ||||
|                                             "Content-Range: bytes 0-%d/%d\r\n" + | ||||
|                                             "Content-Length: %d\r\n" + | ||||
|                                             "Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT\r\n\r\n"; | ||||
|     private static final String CODE_206 = | ||||
|                                             "HTTP/1.0 206 Partial Content\r\n"+ | ||||
|                                             "Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" + | ||||
|                                             "Date: %s\r\n" + | ||||
|                                             "Content-type: application/octet-stream\r\n"+ | ||||
|                                             "Accept-Ranges: bytes\r\n"+ | ||||
|                                             "Content-Range: bytes %d-%d/%d\r\n"+ | ||||
|                                             "Content-Length: %d\r\n"+ | ||||
|                                             "Last-Modified: Mon, 18 Mar 2019 12:57:33 GMT\r\n\r\n"; | ||||
| 
 | ||||
|     public static String getCode200(long nspFileSize){ | ||||
|         return String.format(CODE_200, ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.RFC_1123_DATE_TIME), nspFileSize-1, nspFileSize, nspFileSize); | ||||
|     } | ||||
|     public static String getCode206(long nspFileSize, long startPos, long endPos){ | ||||
|         return String.format(CODE_206, ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.RFC_1123_DATE_TIME), startPos, endPos, nspFileSize, endPos-startPos+1); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -65,7 +65,7 @@ | |||
|                 </Tab> | ||||
|                   <Tab closable="false"> | ||||
|                       <content> | ||||
|                           <fx:include fx:id="NetTab" source="NetTab.fxml" VBox.vgrow="ALWAYS" /> | ||||
|                           <fx:include fx:id="SettingsTab" source="SettingsTab.fxml" VBox.vgrow="ALWAYS" /> | ||||
|                       </content> | ||||
|                      <graphic> | ||||
|                         <SVGPath content="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" /> | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
| <?import javafx.scene.control.TextField?> | ||||
| <?import javafx.scene.layout.VBox?> | ||||
| 
 | ||||
| <VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="150.0" minWidth="150.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.NetTabController"> | ||||
| <VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="150.0" minWidth="150.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.SettingsController"> | ||||
|    <children> | ||||
|       <VBox spacing="5.0"> | ||||
|          <children> | ||||
|  | @ -84,7 +84,7 @@ | |||
|     -fx-background-color: #fefefe; | ||||
| } | ||||
| .dialog-pane > .button-bar > .container{ | ||||
|     -fx-background-color: #2d2d2d; | ||||
|     -fx-background-color: #ebebeb; | ||||
| } | ||||
| 
 | ||||
| .dialog-pane > .label{ | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Dmitry Isaenko
						Dmitry Isaenko