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:
Dmitry Isaenko 2019-03-18 19:12:11 +03:00
parent d55e1c9ba9
commit 9bf4a76076
8 changed files with 191 additions and 46 deletions

View file

@ -88,7 +88,7 @@ Français by [Stephane Meden (JackFromNice)](https://github.com/JackFromNice)
- [ ] XCI support - [ ] XCI support
- [ ] File order sort (non-critical) - [ ] File order sort (non-critical)
- [ ] More deep file analyze before uploading. - [ ] More deep file analyze before uploading.
- [] Network mode support for TinFoil - [x] Network mode support for TinFoil
## Thanks ## Thanks
Appreciate assistance and support of both Vitaliy and Konstantin. Without you all this magic would not have happened. Appreciate assistance and support of both Vitaliy and Konstantin. Without you all this magic would not have happened.

View file

@ -13,12 +13,16 @@ import javafx.stage.FileChooser;
import nsusbloader.AppPreferences; import nsusbloader.AppPreferences;
import nsusbloader.MediatorControl; import nsusbloader.MediatorControl;
import nsusbloader.NET.NETCommunications; import nsusbloader.NET.NETCommunications;
import nsusbloader.NET.NETPacket;
import nsusbloader.NSLMain; import nsusbloader.NSLMain;
import nsusbloader.ServiceWindow; import nsusbloader.ServiceWindow;
import nsusbloader.USB.UsbCommunications; import nsusbloader.USB.UsbCommunications;
import java.io.File; import java.io.File;
import java.net.URL; import java.net.URL;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -47,14 +51,14 @@ public class NSLMainController implements Initializable {
@FXML @FXML
public NSTableViewController tableFilesListController; // Accessible from Mediator public NSTableViewController tableFilesListController; // Accessible from Mediator
@FXML @FXML
private NetTabController NetTabController; private SettingsController SettingsTabController;
@FXML @FXML
private TextField nsIpTextField; private TextField nsIpTextField;
@FXML @FXML
private Label nsIpLbl; private Label nsIpLbl;
private UsbCommunications usbCommunications; private UsbCommunications usbCommunications;
private Thread usbThread; private Thread workThread;
private String previouslyOpenedPath; private String previouslyOpenedPath;
@ -177,7 +181,7 @@ public class NSLMainController implements Initializable {
* It's button listener when no transmission executes * It's button listener when no transmission executes
* */ * */
private void uploadBtnAction(){ private void uploadBtnAction(){
if ((usbThread == null || !usbThread.isAlive())){ if ((workThread == null || !workThread.isAlive())){
if (choiceProtocol.getSelectionModel().getSelectedItem().equals("GoldLeaf") || if (choiceProtocol.getSelectionModel().getSelectedItem().equals("GoldLeaf") ||
( (
choiceProtocol.getSelectionModel().getSelectedItem().equals("TinFoil") choiceProtocol.getSelectionModel().getSelectedItem().equals("TinFoil")
@ -188,26 +192,38 @@ public class NSLMainController implements Initializable {
if ((nspToUpload = tableFilesListController.getFilesForUpload()) == null) { if ((nspToUpload = tableFilesListController.getFilesForUpload()) == null) {
logArea.setText(resourceBundle.getString("logsNoFolderFileSelected")); logArea.setText(resourceBundle.getString("logsNoFolderFileSelected"));
return; return;
}else { }
else {
logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n"); logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n");
for (File item: nspToUpload) for (File item: nspToUpload)
logArea.appendText(" "+item.getAbsolutePath()+"\n"); logArea.appendText(" "+item.getAbsolutePath()+"\n");
} }
usbCommunications = new UsbCommunications(nspToUpload, choiceProtocol.getSelectionModel().getSelectedItem()); usbCommunications = new UsbCommunications(nspToUpload, choiceProtocol.getSelectionModel().getSelectedItem());
usbThread = new Thread(usbCommunications); workThread = new Thread(usbCommunications);
usbThread.setDaemon(true); workThread.setDaemon(true);
usbThread.start(); workThread.start();
} }
else { // NET INSTALL OVER TINFOIL 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"))) if (!ServiceWindow.getConfirmationWindow(resourceBundle.getString("windowTitleBadIp"),resourceBundle.getString("windowBodyBadIp")))
return; return;
String nsIP = nsIpTextField.getText().trim(); String nsIP = nsIpTextField.getText().trim();
if (!NetTabController.getExpertModeSelected()) {
NETCommunications netCommunications = new NETCommunications(nsIP); List<File> nspToUpload;
usbThread = new Thread(netCommunications); if (!SettingsTabController.getExpertModeSelected()) {
usbThread.setDaemon(true); if ((nspToUpload = tableFilesListController.getFilesForUpload()) == null) {
usbThread.start(); 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 { else {
// TODO; pass to another constructor // TODO; pass to another constructor
@ -219,8 +235,8 @@ public class NSLMainController implements Initializable {
* It's button listener when transmission in progress * It's button listener when transmission in progress
* */ * */
private void stopBtnAction(){ private void stopBtnAction(){
if (usbThread != null && usbThread.isAlive()){ if (workThread != null && workThread.isAlive()){
usbCommunications.cancel(false); 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().setRecent(previouslyOpenedPath);
AppPreferences.getInstance().setNetUsb(choiceNetUsb.getSelectionModel().getSelectedItem()); AppPreferences.getInstance().setNetUsb(choiceNetUsb.getSelectionModel().getSelectedItem());
AppPreferences.getInstance().setNsIp(nsIpTextField.getText().trim()); 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());
} }
} }

View file

@ -11,7 +11,7 @@ import nsusbloader.AppPreferences;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class NetTabController implements Initializable { public class SettingsController implements Initializable {
@FXML @FXML
private CheckBox validateNSHostNameCb; private CheckBox validateNSHostNameCb;
@ -25,6 +25,7 @@ public class NetTabController implements Initializable {
@Override @Override
public void initialize(URL url, ResourceBundle resourceBundle) { public void initialize(URL url, ResourceBundle resourceBundle) {
validateNSHostNameCb.setSelected(AppPreferences.getInstance().getNsIpValidationNeeded()); validateNSHostNameCb.setSelected(AppPreferences.getInstance().getNsIpValidationNeeded());
if (AppPreferences.getInstance().getExpertMode()) { if (AppPreferences.getInstance().getExpertMode()) {
expertModeCb.setSelected(true); expertModeCb.setSelected(true);
hostIpLbl.setVisible(true); hostIpLbl.setVisible(true);

View file

@ -1,62 +1,153 @@
package nsusbloader.NET; package nsusbloader.NET;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import nsusbloader.NSLMain;
import java.io.*; import java.io.*;
import java.net.*; 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 String hostIP;
private int hostPort;
private String switchIP; private String switchIP;
private HashMap<String, File> nspMap;
private ServerSocket serverSocket; private ServerSocket serverSocket;
public NETCommunications(String switchIP){ public NETCommunications(List<File> filesList, String switchIP){
this.switchIP = 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 try{ // todo: check other method if internet unavaliable
DatagramSocket socket = new DatagramSocket(); DatagramSocket socket = new DatagramSocket();
socket.connect(InetAddress.getByName("8.8.8.8"), 10002); //193.0.14.129 RIPE NCC socket.connect(InetAddress.getByName("8.8.8.8"), 10002); //193.0.14.129 RIPE NCC
hostIP = socket.getLocalAddress().getHostAddress(); hostIP = socket.getLocalAddress().getHostAddress();
System.out.println(hostIP); //System.out.println(hostIP);
socket.close(); socket.close();
} }
catch (SocketException | UnknownHostException e){ catch (SocketException | UnknownHostException e){
e.printStackTrace(); e.printStackTrace();
} }
this.hostPort = 6000; // TODO: fix
try { try {
serverSocket = new ServerSocket(6000); // TODO: randomize
serverSocket = new ServerSocket(hostPort); // TODO: randomize
//System.out.println(serverSocket.getInetAddress()); 0.0.0.0 //System.out.println(serverSocket.getInetAddress()); 0.0.0.0
} }
catch (IOException ioe){ catch (IOException ioe){
ioe.printStackTrace(); ioe.printStackTrace();
System.out.println("unable to use socket"); System.out.println("unable to use socket");
} }
} }
/*
Replace everything to ASCII (WEB representation)
calculate
write in first 4 bytes
* */
@Override @Override
protected Void call() throws Exception { protected Void call() {
Socket clientSocket = serverSocket.accept(); // Get files list length
StringBuilder myStrBuilder;
InputStream is = clientSocket.getInputStream(); myStrBuilder = new StringBuilder();
InputStreamReader isr = new InputStreamReader(is); for (String fileNameEncoded : nspMap.keySet()) {
BufferedReader br = new BufferedReader(isr); myStrBuilder.append(hostIP);
myStrBuilder.append(':');
OutputStream os = clientSocket.getOutputStream(); myStrBuilder.append(hostPort);
OutputStreamWriter osr = new OutputStreamWriter(os); myStrBuilder.append('/');
PrintWriter pw = new PrintWriter(osr); myStrBuilder.append(fileNameEncoded);
myStrBuilder.append('\n');
String line;
while ((line = br.readLine()) != null) {
if (line.equals("hello world")) {
pw.write("stop doing it!");
pw.flush();
break;
}
System.out.println(line);
} }
serverSocket.close();
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();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
OutputStream os = clientSocket.getOutputStream();
OutputStreamWriter osr = new OutputStreamWriter(os);
PrintWriter pw = new PrintWriter(osr);
String line;
LinkedList<String> tcpPackeet = new LinkedList<>();
while ((line = br.readLine()) != null) {
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
}
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; 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()));
}
}
}
} }

View 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);
}
}

View file

@ -65,7 +65,7 @@
</Tab> </Tab>
<Tab closable="false"> <Tab closable="false">
<content> <content>
<fx:include fx:id="NetTab" source="NetTab.fxml" VBox.vgrow="ALWAYS" /> <fx:include fx:id="SettingsTab" source="SettingsTab.fxml" VBox.vgrow="ALWAYS" />
</content> </content>
<graphic> <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" /> <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" />

View file

@ -6,7 +6,7 @@
<?import javafx.scene.control.TextField?> <?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?> <?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> <children>
<VBox spacing="5.0"> <VBox spacing="5.0">
<children> <children>

View file

@ -84,7 +84,7 @@
-fx-background-color: #fefefe; -fx-background-color: #fefefe;
} }
.dialog-pane > .button-bar > .container{ .dialog-pane > .button-bar > .container{
-fx-background-color: #2d2d2d; -fx-background-color: #ebebeb;
} }
.dialog-pane > .label{ .dialog-pane > .label{