commit c4679645e08df60c1285613c5478e01d0ccb6ce3 Author: Monsterovich Date: Thu Aug 10 00:19:22 2023 +0200 Added project files from original p2pvpn diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..3801343 --- /dev/null +++ b/build.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/P2PVPN.jar b/build/P2PVPN.jar new file mode 100644 index 0000000..b4eb483 Binary files /dev/null and b/build/P2PVPN.jar differ diff --git a/build/classes/org/p2pvpn/Main.class b/build/classes/org/p2pvpn/Main.class new file mode 100644 index 0000000..d460dd3 Binary files /dev/null and b/build/classes/org/p2pvpn/Main.class differ diff --git a/build/classes/org/p2pvpn/gui/AcceptWindow$1.class b/build/classes/org/p2pvpn/gui/AcceptWindow$1.class new file mode 100644 index 0000000..ab2309a Binary files /dev/null and b/build/classes/org/p2pvpn/gui/AcceptWindow$1.class differ diff --git a/build/classes/org/p2pvpn/gui/AcceptWindow$2.class b/build/classes/org/p2pvpn/gui/AcceptWindow$2.class new file mode 100644 index 0000000..2f25e92 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/AcceptWindow$2.class differ diff --git a/build/classes/org/p2pvpn/gui/AcceptWindow$3.class b/build/classes/org/p2pvpn/gui/AcceptWindow$3.class new file mode 100644 index 0000000..f05b5d4 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/AcceptWindow$3.class differ diff --git a/build/classes/org/p2pvpn/gui/AcceptWindow$4.class b/build/classes/org/p2pvpn/gui/AcceptWindow$4.class new file mode 100644 index 0000000..4dcd035 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/AcceptWindow$4.class differ diff --git a/build/classes/org/p2pvpn/gui/AcceptWindow.class b/build/classes/org/p2pvpn/gui/AcceptWindow.class new file mode 100644 index 0000000..13eb28d Binary files /dev/null and b/build/classes/org/p2pvpn/gui/AcceptWindow.class differ diff --git a/build/classes/org/p2pvpn/gui/ChatWindow$1.class b/build/classes/org/p2pvpn/gui/ChatWindow$1.class new file mode 100644 index 0000000..3e431d6 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/ChatWindow$1.class differ diff --git a/build/classes/org/p2pvpn/gui/ChatWindow$ThreadsaveWriteMessage.class b/build/classes/org/p2pvpn/gui/ChatWindow$ThreadsaveWriteMessage.class new file mode 100644 index 0000000..1afec84 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/ChatWindow$ThreadsaveWriteMessage.class differ diff --git a/build/classes/org/p2pvpn/gui/ChatWindow.class b/build/classes/org/p2pvpn/gui/ChatWindow.class new file mode 100644 index 0000000..9391364 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/ChatWindow.class differ diff --git a/build/classes/org/p2pvpn/gui/IPTableModel$1.class b/build/classes/org/p2pvpn/gui/IPTableModel$1.class new file mode 100644 index 0000000..1bb1aed Binary files /dev/null and b/build/classes/org/p2pvpn/gui/IPTableModel$1.class differ diff --git a/build/classes/org/p2pvpn/gui/IPTableModel.class b/build/classes/org/p2pvpn/gui/IPTableModel.class new file mode 100644 index 0000000..5d54cae Binary files /dev/null and b/build/classes/org/p2pvpn/gui/IPTableModel.class differ diff --git a/build/classes/org/p2pvpn/gui/InfoWindow$1.class b/build/classes/org/p2pvpn/gui/InfoWindow$1.class new file mode 100644 index 0000000..4fb55b4 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InfoWindow$1.class differ diff --git a/build/classes/org/p2pvpn/gui/InfoWindow$2.class b/build/classes/org/p2pvpn/gui/InfoWindow$2.class new file mode 100644 index 0000000..3315223 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InfoWindow$2.class differ diff --git a/build/classes/org/p2pvpn/gui/InfoWindow$3.class b/build/classes/org/p2pvpn/gui/InfoWindow$3.class new file mode 100644 index 0000000..011058c Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InfoWindow$3.class differ diff --git a/build/classes/org/p2pvpn/gui/InfoWindow$LoggingWriter.class b/build/classes/org/p2pvpn/gui/InfoWindow$LoggingWriter.class new file mode 100644 index 0000000..340da4d Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InfoWindow$LoggingWriter.class differ diff --git a/build/classes/org/p2pvpn/gui/InfoWindow.class b/build/classes/org/p2pvpn/gui/InfoWindow.class new file mode 100644 index 0000000..9844d75 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InfoWindow.class differ diff --git a/build/classes/org/p2pvpn/gui/InviteWindow$1.class b/build/classes/org/p2pvpn/gui/InviteWindow$1.class new file mode 100644 index 0000000..6a8f8b8 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InviteWindow$1.class differ diff --git a/build/classes/org/p2pvpn/gui/InviteWindow$2.class b/build/classes/org/p2pvpn/gui/InviteWindow$2.class new file mode 100644 index 0000000..c272a5b Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InviteWindow$2.class differ diff --git a/build/classes/org/p2pvpn/gui/InviteWindow$3.class b/build/classes/org/p2pvpn/gui/InviteWindow$3.class new file mode 100644 index 0000000..711ba17 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InviteWindow$3.class differ diff --git a/build/classes/org/p2pvpn/gui/InviteWindow$4.class b/build/classes/org/p2pvpn/gui/InviteWindow$4.class new file mode 100644 index 0000000..b47fd75 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InviteWindow$4.class differ diff --git a/build/classes/org/p2pvpn/gui/InviteWindow$5.class b/build/classes/org/p2pvpn/gui/InviteWindow$5.class new file mode 100644 index 0000000..fa1ab14 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InviteWindow$5.class differ diff --git a/build/classes/org/p2pvpn/gui/InviteWindow.class b/build/classes/org/p2pvpn/gui/InviteWindow.class new file mode 100644 index 0000000..6edee1e Binary files /dev/null and b/build/classes/org/p2pvpn/gui/InviteWindow.class differ diff --git a/build/classes/org/p2pvpn/gui/MainControl.class b/build/classes/org/p2pvpn/gui/MainControl.class new file mode 100644 index 0000000..f3c46db Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainControl.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$1.class b/build/classes/org/p2pvpn/gui/MainWindow$1.class new file mode 100644 index 0000000..cec7e7f Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$1.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$10.class b/build/classes/org/p2pvpn/gui/MainWindow$10.class new file mode 100644 index 0000000..9e2eeca Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$10.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$11.class b/build/classes/org/p2pvpn/gui/MainWindow$11.class new file mode 100644 index 0000000..7d48807 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$11.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$12.class b/build/classes/org/p2pvpn/gui/MainWindow$12.class new file mode 100644 index 0000000..083da6c Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$12.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$2.class b/build/classes/org/p2pvpn/gui/MainWindow$2.class new file mode 100644 index 0000000..d2a44e8 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$2.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$3.class b/build/classes/org/p2pvpn/gui/MainWindow$3.class new file mode 100644 index 0000000..d22337a Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$3.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$4.class b/build/classes/org/p2pvpn/gui/MainWindow$4.class new file mode 100644 index 0000000..49127a2 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$4.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$5.class b/build/classes/org/p2pvpn/gui/MainWindow$5.class new file mode 100644 index 0000000..61a245d Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$5.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$6.class b/build/classes/org/p2pvpn/gui/MainWindow$6.class new file mode 100644 index 0000000..ddfc7d1 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$6.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$7.class b/build/classes/org/p2pvpn/gui/MainWindow$7.class new file mode 100644 index 0000000..b5e15aa Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$7.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$8.class b/build/classes/org/p2pvpn/gui/MainWindow$8.class new file mode 100644 index 0000000..f7bf319 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$8.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$9.class b/build/classes/org/p2pvpn/gui/MainWindow$9.class new file mode 100644 index 0000000..43707bd Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$9.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow$PopupMenuListener.class b/build/classes/org/p2pvpn/gui/MainWindow$PopupMenuListener.class new file mode 100644 index 0000000..39075af Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow$PopupMenuListener.class differ diff --git a/build/classes/org/p2pvpn/gui/MainWindow.class b/build/classes/org/p2pvpn/gui/MainWindow.class new file mode 100644 index 0000000..50da9f2 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/MainWindow.class differ diff --git a/build/classes/org/p2pvpn/gui/NewNetwork$1.class b/build/classes/org/p2pvpn/gui/NewNetwork$1.class new file mode 100644 index 0000000..bd5f689 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/NewNetwork$1.class differ diff --git a/build/classes/org/p2pvpn/gui/NewNetwork$2.class b/build/classes/org/p2pvpn/gui/NewNetwork$2.class new file mode 100644 index 0000000..81185eb Binary files /dev/null and b/build/classes/org/p2pvpn/gui/NewNetwork$2.class differ diff --git a/build/classes/org/p2pvpn/gui/NewNetwork$3.class b/build/classes/org/p2pvpn/gui/NewNetwork$3.class new file mode 100644 index 0000000..ec237b6 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/NewNetwork$3.class differ diff --git a/build/classes/org/p2pvpn/gui/NewNetwork.class b/build/classes/org/p2pvpn/gui/NewNetwork.class new file mode 100644 index 0000000..80b72d0 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/NewNetwork.class differ diff --git a/build/classes/org/p2pvpn/gui/OptionWindow$1.class b/build/classes/org/p2pvpn/gui/OptionWindow$1.class new file mode 100644 index 0000000..bdcdee2 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/OptionWindow$1.class differ diff --git a/build/classes/org/p2pvpn/gui/OptionWindow$2.class b/build/classes/org/p2pvpn/gui/OptionWindow$2.class new file mode 100644 index 0000000..4b54d65 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/OptionWindow$2.class differ diff --git a/build/classes/org/p2pvpn/gui/OptionWindow$3.class b/build/classes/org/p2pvpn/gui/OptionWindow$3.class new file mode 100644 index 0000000..05edefb Binary files /dev/null and b/build/classes/org/p2pvpn/gui/OptionWindow$3.class differ diff --git a/build/classes/org/p2pvpn/gui/OptionWindow$4.class b/build/classes/org/p2pvpn/gui/OptionWindow$4.class new file mode 100644 index 0000000..b82e859 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/OptionWindow$4.class differ diff --git a/build/classes/org/p2pvpn/gui/OptionWindow.class b/build/classes/org/p2pvpn/gui/OptionWindow.class new file mode 100644 index 0000000..5935db7 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/OptionWindow.class differ diff --git a/build/classes/org/p2pvpn/gui/PeerGraph.class b/build/classes/org/p2pvpn/gui/PeerGraph.class new file mode 100644 index 0000000..ed3e5d0 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/PeerGraph.class differ diff --git a/build/classes/org/p2pvpn/gui/PeerListCellRenderer.class b/build/classes/org/p2pvpn/gui/PeerListCellRenderer.class new file mode 100644 index 0000000..bca6c9e Binary files /dev/null and b/build/classes/org/p2pvpn/gui/PeerListCellRenderer.class differ diff --git a/build/classes/org/p2pvpn/gui/PeerListModel$1.class b/build/classes/org/p2pvpn/gui/PeerListModel$1.class new file mode 100644 index 0000000..b4b356e Binary files /dev/null and b/build/classes/org/p2pvpn/gui/PeerListModel$1.class differ diff --git a/build/classes/org/p2pvpn/gui/PeerListModel.class b/build/classes/org/p2pvpn/gui/PeerListModel.class new file mode 100644 index 0000000..7f59585 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/PeerListModel.class differ diff --git a/build/classes/org/p2pvpn/gui/PeerTableModel$1.class b/build/classes/org/p2pvpn/gui/PeerTableModel$1.class new file mode 100644 index 0000000..3739857 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/PeerTableModel$1.class differ diff --git a/build/classes/org/p2pvpn/gui/PeerTableModel$2.class b/build/classes/org/p2pvpn/gui/PeerTableModel$2.class new file mode 100644 index 0000000..d2f6c88 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/PeerTableModel$2.class differ diff --git a/build/classes/org/p2pvpn/gui/PeerTableModel.class b/build/classes/org/p2pvpn/gui/PeerTableModel.class new file mode 100644 index 0000000..7bfe3c7 Binary files /dev/null and b/build/classes/org/p2pvpn/gui/PeerTableModel.class differ diff --git a/build/classes/org/p2pvpn/network/ConnectionManager$1.class b/build/classes/org/p2pvpn/network/ConnectionManager$1.class new file mode 100644 index 0000000..ad4cadd Binary files /dev/null and b/build/classes/org/p2pvpn/network/ConnectionManager$1.class differ diff --git a/build/classes/org/p2pvpn/network/ConnectionManager$2.class b/build/classes/org/p2pvpn/network/ConnectionManager$2.class new file mode 100644 index 0000000..bd4b7d2 Binary files /dev/null and b/build/classes/org/p2pvpn/network/ConnectionManager$2.class differ diff --git a/build/classes/org/p2pvpn/network/ConnectionManager$ConnectTask.class b/build/classes/org/p2pvpn/network/ConnectionManager$ConnectTask.class new file mode 100644 index 0000000..1902283 Binary files /dev/null and b/build/classes/org/p2pvpn/network/ConnectionManager$ConnectTask.class differ diff --git a/build/classes/org/p2pvpn/network/ConnectionManager.class b/build/classes/org/p2pvpn/network/ConnectionManager.class new file mode 100644 index 0000000..fade558 Binary files /dev/null and b/build/classes/org/p2pvpn/network/ConnectionManager.class differ diff --git a/build/classes/org/p2pvpn/network/Connector$AddIPLater.class b/build/classes/org/p2pvpn/network/Connector$AddIPLater.class new file mode 100644 index 0000000..30ca623 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Connector$AddIPLater.class differ diff --git a/build/classes/org/p2pvpn/network/Connector$ConnectRunnable.class b/build/classes/org/p2pvpn/network/Connector$ConnectRunnable.class new file mode 100644 index 0000000..e81f51c Binary files /dev/null and b/build/classes/org/p2pvpn/network/Connector$ConnectRunnable.class differ diff --git a/build/classes/org/p2pvpn/network/Connector$Endpoint.class b/build/classes/org/p2pvpn/network/Connector$Endpoint.class new file mode 100644 index 0000000..4fc83b5 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Connector$Endpoint.class differ diff --git a/build/classes/org/p2pvpn/network/Connector$EndpointInfo.class b/build/classes/org/p2pvpn/network/Connector$EndpointInfo.class new file mode 100644 index 0000000..9e5d8e2 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Connector$EndpointInfo.class differ diff --git a/build/classes/org/p2pvpn/network/Connector.class b/build/classes/org/p2pvpn/network/Connector.class new file mode 100644 index 0000000..634d6e7 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Connector.class differ diff --git a/build/classes/org/p2pvpn/network/ConnectorListener.class b/build/classes/org/p2pvpn/network/ConnectorListener.class new file mode 100644 index 0000000..6c8cd57 Binary files /dev/null and b/build/classes/org/p2pvpn/network/ConnectorListener.class differ diff --git a/build/classes/org/p2pvpn/network/InternalPacketListener.class b/build/classes/org/p2pvpn/network/InternalPacketListener.class new file mode 100644 index 0000000..be7b4f1 Binary files /dev/null and b/build/classes/org/p2pvpn/network/InternalPacketListener.class differ diff --git a/build/classes/org/p2pvpn/network/MacAddress.class b/build/classes/org/p2pvpn/network/MacAddress.class new file mode 100644 index 0000000..f819817 Binary files /dev/null and b/build/classes/org/p2pvpn/network/MacAddress.class differ diff --git a/build/classes/org/p2pvpn/network/P2PConnection$1.class b/build/classes/org/p2pvpn/network/P2PConnection$1.class new file mode 100644 index 0000000..3acd18f Binary files /dev/null and b/build/classes/org/p2pvpn/network/P2PConnection$1.class differ diff --git a/build/classes/org/p2pvpn/network/P2PConnection$2.class b/build/classes/org/p2pvpn/network/P2PConnection$2.class new file mode 100644 index 0000000..1abd539 Binary files /dev/null and b/build/classes/org/p2pvpn/network/P2PConnection$2.class differ diff --git a/build/classes/org/p2pvpn/network/P2PConnection$P2PConnState.class b/build/classes/org/p2pvpn/network/P2PConnection$P2PConnState.class new file mode 100644 index 0000000..9ba624a Binary files /dev/null and b/build/classes/org/p2pvpn/network/P2PConnection$P2PConnState.class differ diff --git a/build/classes/org/p2pvpn/network/P2PConnection.class b/build/classes/org/p2pvpn/network/P2PConnection.class new file mode 100644 index 0000000..8422b93 Binary files /dev/null and b/build/classes/org/p2pvpn/network/P2PConnection.class differ diff --git a/build/classes/org/p2pvpn/network/PeerID.class b/build/classes/org/p2pvpn/network/PeerID.class new file mode 100644 index 0000000..370c205 Binary files /dev/null and b/build/classes/org/p2pvpn/network/PeerID.class differ diff --git a/build/classes/org/p2pvpn/network/Pinger$1.class b/build/classes/org/p2pvpn/network/Pinger$1.class new file mode 100644 index 0000000..c70be2a Binary files /dev/null and b/build/classes/org/p2pvpn/network/Pinger$1.class differ diff --git a/build/classes/org/p2pvpn/network/Pinger$PingInfo.class b/build/classes/org/p2pvpn/network/Pinger$PingInfo.class new file mode 100644 index 0000000..cb0d892 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Pinger$PingInfo.class differ diff --git a/build/classes/org/p2pvpn/network/Pinger.class b/build/classes/org/p2pvpn/network/Pinger.class new file mode 100644 index 0000000..b872b68 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Pinger.class differ diff --git a/build/classes/org/p2pvpn/network/Router$1.class b/build/classes/org/p2pvpn/network/Router$1.class new file mode 100644 index 0000000..7fa440f Binary files /dev/null and b/build/classes/org/p2pvpn/network/Router$1.class differ diff --git a/build/classes/org/p2pvpn/network/Router$2.class b/build/classes/org/p2pvpn/network/Router$2.class new file mode 100644 index 0000000..3223db7 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Router$2.class differ diff --git a/build/classes/org/p2pvpn/network/Router.class b/build/classes/org/p2pvpn/network/Router.class new file mode 100644 index 0000000..33e2359 Binary files /dev/null and b/build/classes/org/p2pvpn/network/Router.class differ diff --git a/build/classes/org/p2pvpn/network/RoutungTableListener.class b/build/classes/org/p2pvpn/network/RoutungTableListener.class new file mode 100644 index 0000000..eb5e8dd Binary files /dev/null and b/build/classes/org/p2pvpn/network/RoutungTableListener.class differ diff --git a/build/classes/org/p2pvpn/network/TCPConnection$1.class b/build/classes/org/p2pvpn/network/TCPConnection$1.class new file mode 100644 index 0000000..e209624 Binary files /dev/null and b/build/classes/org/p2pvpn/network/TCPConnection$1.class differ diff --git a/build/classes/org/p2pvpn/network/TCPConnection$2.class b/build/classes/org/p2pvpn/network/TCPConnection$2.class new file mode 100644 index 0000000..750a64b Binary files /dev/null and b/build/classes/org/p2pvpn/network/TCPConnection$2.class differ diff --git a/build/classes/org/p2pvpn/network/TCPConnection$CCState.class b/build/classes/org/p2pvpn/network/TCPConnection$CCState.class new file mode 100644 index 0000000..f644572 Binary files /dev/null and b/build/classes/org/p2pvpn/network/TCPConnection$CCState.class differ diff --git a/build/classes/org/p2pvpn/network/TCPConnection.class b/build/classes/org/p2pvpn/network/TCPConnection.class new file mode 100644 index 0000000..9e7084b Binary files /dev/null and b/build/classes/org/p2pvpn/network/TCPConnection.class differ diff --git a/build/classes/org/p2pvpn/network/UPnPPortForward.class b/build/classes/org/p2pvpn/network/UPnPPortForward.class new file mode 100644 index 0000000..06729e7 Binary files /dev/null and b/build/classes/org/p2pvpn/network/UPnPPortForward.class differ diff --git a/build/classes/org/p2pvpn/network/UPnPPortForwardListener.class b/build/classes/org/p2pvpn/network/UPnPPortForwardListener.class new file mode 100644 index 0000000..607ac07 Binary files /dev/null and b/build/classes/org/p2pvpn/network/UPnPPortForwardListener.class differ diff --git a/build/classes/org/p2pvpn/network/VPNConnector.class b/build/classes/org/p2pvpn/network/VPNConnector.class new file mode 100644 index 0000000..6ae32ea Binary files /dev/null and b/build/classes/org/p2pvpn/network/VPNConnector.class differ diff --git a/build/classes/org/p2pvpn/network/bandwidth/MeasureBandwidth.class b/build/classes/org/p2pvpn/network/bandwidth/MeasureBandwidth.class new file mode 100644 index 0000000..1df4387 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bandwidth/MeasureBandwidth.class differ diff --git a/build/classes/org/p2pvpn/network/bandwidth/SlidingAverage.class b/build/classes/org/p2pvpn/network/bandwidth/SlidingAverage.class new file mode 100644 index 0000000..9d1b9ea Binary files /dev/null and b/build/classes/org/p2pvpn/network/bandwidth/SlidingAverage.class differ diff --git a/build/classes/org/p2pvpn/network/bandwidth/TokenBucket.class b/build/classes/org/p2pvpn/network/bandwidth/TokenBucket.class new file mode 100644 index 0000000..4501370 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bandwidth/TokenBucket.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/BitTorrentTracker.class b/build/classes/org/p2pvpn/network/bittorrent/BitTorrentTracker.class new file mode 100644 index 0000000..1a5083d Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/BitTorrentTracker.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/Contact.class b/build/classes/org/p2pvpn/network/bittorrent/Contact.class new file mode 100644 index 0000000..741ed3e Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/Contact.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/DHT$1.class b/build/classes/org/p2pvpn/network/bittorrent/DHT$1.class new file mode 100644 index 0000000..50f6505 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/DHT$1.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/DHT$2.class b/build/classes/org/p2pvpn/network/bittorrent/DHT$2.class new file mode 100644 index 0000000..304afc5 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/DHT$2.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/DHT.class b/build/classes/org/p2pvpn/network/bittorrent/DHT.class new file mode 100644 index 0000000..9846ab4 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/DHT.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/RoutingTable.class b/build/classes/org/p2pvpn/network/bittorrent/RoutingTable.class new file mode 100644 index 0000000..127ea33 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/RoutingTable.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/RoutingTableLeaf.class b/build/classes/org/p2pvpn/network/bittorrent/RoutingTableLeaf.class new file mode 100644 index 0000000..1709832 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/RoutingTableLeaf.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/RoutingTableNode.class b/build/classes/org/p2pvpn/network/bittorrent/RoutingTableNode.class new file mode 100644 index 0000000..992b14c Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/RoutingTableNode.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/bencode/Bencode.class b/build/classes/org/p2pvpn/network/bittorrent/bencode/Bencode.class new file mode 100644 index 0000000..2326135 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/bencode/Bencode.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeInt.class b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeInt.class new file mode 100644 index 0000000..c3d171e Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeInt.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeList.class b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeList.class new file mode 100644 index 0000000..95964ac Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeList.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeMap.class b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeMap.class new file mode 100644 index 0000000..f6509c3 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeMap.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeObject.class b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeObject.class new file mode 100644 index 0000000..6a33ccf Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeObject.class differ diff --git a/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeString.class b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeString.class new file mode 100644 index 0000000..f9d6343 Binary files /dev/null and b/build/classes/org/p2pvpn/network/bittorrent/bencode/BencodeString.class differ diff --git a/build/classes/org/p2pvpn/tools/AdapterManager.class b/build/classes/org/p2pvpn/tools/AdapterManager.class new file mode 100644 index 0000000..29776be Binary files /dev/null and b/build/classes/org/p2pvpn/tools/AdapterManager.class differ diff --git a/build/classes/org/p2pvpn/tools/AdvProperties.class b/build/classes/org/p2pvpn/tools/AdvProperties.class new file mode 100644 index 0000000..b7d196f Binary files /dev/null and b/build/classes/org/p2pvpn/tools/AdvProperties.class differ diff --git a/build/classes/org/p2pvpn/tools/CryptoUtils.class b/build/classes/org/p2pvpn/tools/CryptoUtils.class new file mode 100644 index 0000000..4c99b45 Binary files /dev/null and b/build/classes/org/p2pvpn/tools/CryptoUtils.class differ diff --git a/build/classes/org/p2pvpn/tools/ProfileManager$1.class b/build/classes/org/p2pvpn/tools/ProfileManager$1.class new file mode 100644 index 0000000..fc8a2c8 Binary files /dev/null and b/build/classes/org/p2pvpn/tools/ProfileManager$1.class differ diff --git a/build/classes/org/p2pvpn/tools/ProfileManager$ProfileDescription.class b/build/classes/org/p2pvpn/tools/ProfileManager$ProfileDescription.class new file mode 100644 index 0000000..bb343b4 Binary files /dev/null and b/build/classes/org/p2pvpn/tools/ProfileManager$ProfileDescription.class differ diff --git a/build/classes/org/p2pvpn/tools/ProfileManager.class b/build/classes/org/p2pvpn/tools/ProfileManager.class new file mode 100644 index 0000000..11317db Binary files /dev/null and b/build/classes/org/p2pvpn/tools/ProfileManager.class differ diff --git a/build/classes/org/p2pvpn/tools/SocketAddrStr.class b/build/classes/org/p2pvpn/tools/SocketAddrStr.class new file mode 100644 index 0000000..ff4562e Binary files /dev/null and b/build/classes/org/p2pvpn/tools/SocketAddrStr.class differ diff --git a/build/classes/org/p2pvpn/tools/VersionizedMap.class b/build/classes/org/p2pvpn/tools/VersionizedMap.class new file mode 100644 index 0000000..747662d Binary files /dev/null and b/build/classes/org/p2pvpn/tools/VersionizedMap.class differ diff --git a/build/classes/org/p2pvpn/tuntap/TunTap.class b/build/classes/org/p2pvpn/tuntap/TunTap.class new file mode 100644 index 0000000..ca77540 Binary files /dev/null and b/build/classes/org/p2pvpn/tuntap/TunTap.class differ diff --git a/build/classes/org/p2pvpn/tuntap/TunTapLinux.class b/build/classes/org/p2pvpn/tuntap/TunTapLinux.class new file mode 100644 index 0000000..881a793 Binary files /dev/null and b/build/classes/org/p2pvpn/tuntap/TunTapLinux.class differ diff --git a/build/classes/org/p2pvpn/tuntap/TunTapWindows.class b/build/classes/org/p2pvpn/tuntap/TunTapWindows.class new file mode 100644 index 0000000..c05770e Binary files /dev/null and b/build/classes/org/p2pvpn/tuntap/TunTapWindows.class differ diff --git a/build/classes/test/org/p2pvpn/tools/TestAdvProperties.class b/build/classes/test/org/p2pvpn/tools/TestAdvProperties.class new file mode 100644 index 0000000..4c2434f Binary files /dev/null and b/build/classes/test/org/p2pvpn/tools/TestAdvProperties.class differ diff --git a/build/clib/libTunTapLinux.so b/build/clib/libTunTapLinux.so new file mode 100644 index 0000000..e83c006 Binary files /dev/null and b/build/clib/libTunTapLinux.so differ diff --git a/build/clib/libTunTapWindows.dll b/build/clib/libTunTapWindows.dll new file mode 100644 index 0000000..be17ed3 Binary files /dev/null and b/build/clib/libTunTapWindows.dll differ diff --git a/build/clib/libTunTapWindows64.dll b/build/clib/libTunTapWindows64.dll new file mode 100644 index 0000000..2c56347 Binary files /dev/null and b/build/clib/libTunTapWindows64.dll differ diff --git a/build/lib/bcprov-jdk15on-1.70.jar b/build/lib/bcprov-jdk15on-1.70.jar new file mode 100644 index 0000000..0e4198e Binary files /dev/null and b/build/lib/bcprov-jdk15on-1.70.jar differ diff --git a/build/lib/commons-codec-1.3.jar b/build/lib/commons-codec-1.3.jar new file mode 100644 index 0000000..957b675 Binary files /dev/null and b/build/lib/commons-codec-1.3.jar differ diff --git a/build/lib/commons-jxpath-1.1.jar b/build/lib/commons-jxpath-1.1.jar new file mode 100644 index 0000000..9516e2a Binary files /dev/null and b/build/lib/commons-jxpath-1.1.jar differ diff --git a/build/lib/commons-logging.jar b/build/lib/commons-logging.jar new file mode 100644 index 0000000..b99c937 Binary files /dev/null and b/build/lib/commons-logging.jar differ diff --git a/build/lib/junit-4.5.jar b/build/lib/junit-4.5.jar new file mode 100644 index 0000000..7339216 Binary files /dev/null and b/build/lib/junit-4.5.jar differ diff --git a/build/lib/swing-layout-1.0.3.jar b/build/lib/swing-layout-1.0.3.jar new file mode 100644 index 0000000..6e1b43b Binary files /dev/null and b/build/lib/swing-layout-1.0.3.jar differ diff --git a/clib/libTunTapLinux.so b/clib/libTunTapLinux.so new file mode 100755 index 0000000..e83c006 Binary files /dev/null and b/clib/libTunTapLinux.so differ diff --git a/clib/libTunTapWindows.dll b/clib/libTunTapWindows.dll new file mode 100644 index 0000000..be17ed3 Binary files /dev/null and b/clib/libTunTapWindows.dll differ diff --git a/clib/libTunTapWindows64.dll b/clib/libTunTapWindows64.dll new file mode 100644 index 0000000..2c56347 Binary files /dev/null and b/clib/libTunTapWindows64.dll differ diff --git a/lib/bcprov-jdk15on-1.70.jar b/lib/bcprov-jdk15on-1.70.jar new file mode 100644 index 0000000..0e4198e Binary files /dev/null and b/lib/bcprov-jdk15on-1.70.jar differ diff --git a/lib/commons-codec-1.3.jar b/lib/commons-codec-1.3.jar new file mode 100644 index 0000000..957b675 Binary files /dev/null and b/lib/commons-codec-1.3.jar differ diff --git a/lib/commons-jxpath-1.1.jar b/lib/commons-jxpath-1.1.jar new file mode 100644 index 0000000..9516e2a Binary files /dev/null and b/lib/commons-jxpath-1.1.jar differ diff --git a/lib/commons-logging.jar b/lib/commons-logging.jar new file mode 100644 index 0000000..b99c937 Binary files /dev/null and b/lib/commons-logging.jar differ diff --git a/lib/junit-4.5.jar b/lib/junit-4.5.jar new file mode 100644 index 0000000..7339216 Binary files /dev/null and b/lib/junit-4.5.jar differ diff --git a/lib/swing-layout-1.0.3.jar b/lib/swing-layout-1.0.3.jar new file mode 100644 index 0000000..6e1b43b Binary files /dev/null and b/lib/swing-layout-1.0.3.jar differ diff --git a/manifest.mf b/manifest.mf new file mode 100644 index 0000000..1574df4 --- /dev/null +++ b/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/native/tapLinux/Makefile b/native/tapLinux/Makefile new file mode 100644 index 0000000..acd23c3 --- /dev/null +++ b/native/tapLinux/Makefile @@ -0,0 +1,92 @@ +# +# There exist several targets which are by default empty and which can be +# used for execution of your targets. These targets are usually executed +# before and after some main targets. They are: +# +# .build-pre: called before 'build' target +# .build-post: called after 'build' target +# .clean-pre: called before 'clean' target +# .clean-post: called after 'clean' target +# .clobber-pre: called before 'clobber' target +# .clobber-post: called after 'clobber' target +# .all-pre: called before 'all' target +# .all-post: called after 'all' target +# .help-pre: called before 'help' target +# .help-post: called after 'help' target +# +# Targets beginning with '.' are not intended to be called on their own. +# +# Main targets can be executed directly, and they are: +# +# build build a specific configuration +# clean remove built files from a configuration +# clobber remove all built files +# all build all configurations +# help print help mesage +# +# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and +# .help-impl are implemented in nbproject/makefile-impl.mk. +# +# NOCDDL + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib + + +# build +build: .build-pre .build-impl .build-post + +.build-pre: +# Add your pre 'build' code here... + +.build-post: +# Add your post 'build' code here... + + +# clean +clean: .clean-pre .clean-impl .clean-post + +.clean-pre: +# Add your pre 'clean' code here... + +.clean-post: +# Add your post 'clean' code here... + + +# clobber +clobber: .clobber-pre .clobber-impl .clobber-post + +.clobber-pre: +# Add your pre 'clobber' code here... + +.clobber-post: +# Add your post 'clobber' code here... + + +# all +all: .all-pre .all-impl .all-post + +.all-pre: +# Add your pre 'all' code here... + +.all-post: +# Add your post 'all' code here... + + +# help +help: .help-pre .help-impl .help-post + +.help-pre: +# Add your pre 'help' code here... + +.help-post: +# Add your post 'help' code here... + + + +# include project implementation makefile +include nbproject/Makefile-impl.mk diff --git a/native/tapLinux/nbproject/Makefile-Debug.mk b/native/tapLinux/nbproject/Makefile-Debug.mk new file mode 100644 index 0000000..5438760 --- /dev/null +++ b/native/tapLinux/nbproject/Makefile-Debug.mk @@ -0,0 +1,63 @@ +# +# Gererated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC= +CXX= +FC= + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=build/Debug/GNU-Linux-x86 + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapLinux.o + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS= +CXXFLAGS= + +# Fortran Compiler Flags +FFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS= + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} dist/Debug/GNU-Linux-x86/libTunTapLinux.so + +dist/Debug/GNU-Linux-x86/libTunTapLinux.so: ${OBJECTFILES} + ${MKDIR} -p dist/Debug/GNU-Linux-x86 + ${LINK.c} -shared -o dist/Debug/GNU-Linux-x86/libTunTapLinux.so -fPIC ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/org_p2pvpn_tuntap_TunTapLinux.o: org_p2pvpn_tuntap_TunTapLinux.c + ${MKDIR} -p ${OBJECTDIR} + $(COMPILE.c) -g -I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux -fPIC -o ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapLinux.o org_p2pvpn_tuntap_TunTapLinux.c + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: + ${RM} -r build/Debug + ${RM} dist/Debug/GNU-Linux-x86/libTunTapLinux.so + +# Subprojects +.clean-subprojects: diff --git a/native/tapLinux/nbproject/Makefile-Release.mk b/native/tapLinux/nbproject/Makefile-Release.mk new file mode 100644 index 0000000..9e4c533 --- /dev/null +++ b/native/tapLinux/nbproject/Makefile-Release.mk @@ -0,0 +1,63 @@ +# +# Gererated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC= +CXX= +FC= + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=build/Release/GNU-Linux-x86 + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapLinux.o + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS= +CXXFLAGS= + +# Fortran Compiler Flags +FFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS= + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} dist/Release/GNU-Linux-x86/libtrunk.so + +dist/Release/GNU-Linux-x86/libtrunk.so: ${OBJECTFILES} + ${MKDIR} -p dist/Release/GNU-Linux-x86 + ${LINK.c} -shared -o dist/Release/GNU-Linux-x86/libtrunk.so -fPIC ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/org_p2pvpn_tuntap_TunTapLinux.o: org_p2pvpn_tuntap_TunTapLinux.c + ${MKDIR} -p ${OBJECTDIR} + $(COMPILE.c) -O2 -fPIC -o ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapLinux.o org_p2pvpn_tuntap_TunTapLinux.c + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: + ${RM} -r build/Release + ${RM} dist/Release/GNU-Linux-x86/libtrunk.so + +# Subprojects +.clean-subprojects: diff --git a/native/tapLinux/nbproject/Makefile-impl.mk b/native/tapLinux/nbproject/Makefile-impl.mk new file mode 100644 index 0000000..2674c7c --- /dev/null +++ b/native/tapLinux/nbproject/Makefile-impl.mk @@ -0,0 +1,111 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a pre- and a post- target defined where you can add customization code. +# +# This makefile implements macros and targets common to all configurations. +# +# NOCDDL + + +# Building and Cleaning subprojects are done by default, but can be controlled with the SUB +# macro. If SUB=no, subprojects will not be built or cleaned. The following macro +# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf +# and .clean-reqprojects-conf unless SUB has the value 'no' +SUB_no=NO +SUBPROJECTS=${SUB_${SUB}} +BUILD_SUBPROJECTS_=.build-subprojects +BUILD_SUBPROJECTS_NO= +BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} +CLEAN_SUBPROJECTS_=.clean-subprojects +CLEAN_SUBPROJECTS_NO= +CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} + + +# Project Name +PROJECTNAME=trunk + +# Active Configuration +DEFAULTCONF=Debug +CONF=${DEFAULTCONF} + +# All Configurations +ALLCONFS=Debug Release + + +# build +.build-impl: .validate-impl + @#echo "=> Running $@... Configuration=$(CONF)" + ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf + + +# clean +.clean-impl: .validate-impl + @#echo "=> Running $@... Configuration=$(CONF)" + ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf + + +# clobber +.clobber-impl: + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + ${MAKE} -f nbproject/Makefile-$${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf; \ + done + +# all +.all-impl: + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + ${MAKE} -f nbproject/Makefile-$${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf; \ + done + + +# configuration validation +.validate-impl: + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + echo ""; \ + echo "Error: can not find the makefile for configuration '${CONF}' in project ${PROJECTNAME}"; \ + echo "See 'make help' for details."; \ + echo "Current directory: " `pwd`; \ + echo ""; \ + fi + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + exit 1; \ + fi + + +# help +.help-impl: + @echo "This makefile supports the following configurations:" + @echo " ${ALLCONFS}" + @echo "" + @echo "and the following targets:" + @echo " build (default target)" + @echo " clean" + @echo " clobber" + @echo " all" + @echo " help" + @echo "" + @echo "Makefile Usage:" + @echo " make [CONF=] [SUB=no] build" + @echo " make [CONF=] [SUB=no] clean" + @echo " make [SUB=no] clobber" + @echo " make [SUB=no] all" + @echo " make help" + @echo "" + @echo "Target 'build' will build a specific configuration and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'clean' will clean a specific configuration and, unless 'SUB=no'," + @echo " also clean subprojects." + @echo "Target 'clobber' will remove all built files from all configurations and," + @echo " unless 'SUB=no', also from subprojects." + @echo "Target 'all' will will build all configurations and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'help' prints this message." + @echo "" + diff --git a/native/tapLinux/nbproject/configurations.xml b/native/tapLinux/nbproject/configurations.xml new file mode 100644 index 0000000..4123e52 --- /dev/null +++ b/native/tapLinux/nbproject/configurations.xml @@ -0,0 +1,82 @@ + + + + + org_p2pvpn_tuntap_TunTapLinux.h + + + + + org_p2pvpn_tuntap_TunTapLinux.c + + + Makefile + + + UTF-8 + Makefile + + + + GNU|GNU + 2 + + + + + /usr/lib/jvm/java-6-sun-1.6.0.07/include/linux + /usr/lib/jvm/java-6-sun-1.6.0.07/include + /usr/lib/jvm/java-6-sun-1.6.0.03/include/linux + /usr/lib/jvm/java-6-sun-1.6.0.03/include + + + + dist/Debug/GNU-Linux-x86/libTunTapLinux.so + + + + + + 0 + + + 3 + + + + + GNU|GNU + 2 + + + + 5 + + + 5 + + + 5 + + + + + + + + 0 + + + 3 + + + + diff --git a/native/tapLinux/nbproject/project.properties b/native/tapLinux/nbproject/project.properties new file mode 100644 index 0000000..e69de29 diff --git a/native/tapLinux/nbproject/project.xml b/native/tapLinux/nbproject/project.xml new file mode 100644 index 0000000..99c2c72 --- /dev/null +++ b/native/tapLinux/nbproject/project.xml @@ -0,0 +1,11 @@ + + + org.netbeans.modules.cnd.makeproject + + + tabLinux + 0 + + + + diff --git a/native/tapLinux/org_p2pvpn_tuntap_TunTapLinux.c b/native/tapLinux/org_p2pvpn_tuntap_TunTapLinux.c new file mode 100644 index 0000000..144a6e4 --- /dev/null +++ b/native/tapLinux/org_p2pvpn_tuntap_TunTapLinux.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "org_p2pvpn_tuntap_TunTapLinux.h" + +void setFdDev(JNIEnv *env, jobject this, int fd, char* dev) { + jfieldID jfd, jdev; + jclass jclass; + jstring jstr; + + jclass = (*env)->GetObjectClass(env, this); + + jfd = (*env)->GetFieldID(env, jclass, "fd", "I"); + (*env)->SetIntField(env, this, jfd , fd); + + jstr = (*env)->NewStringUTF(env, dev); + jdev = (*env)->GetFieldID(env, jclass, "dev", "Ljava/lang/String;"); + (*env)->SetObjectField(env, this, jdev , jstr); +} + +int getFd(JNIEnv *env, jobject this) { + jfieldID jfd; + jclass jclass; + + jclass = (*env)->GetObjectClass(env, this); + + jfd = (*env)->GetFieldID(env, jclass, "fd", "I"); + return (*env)->GetIntField(env, this, jfd); +} + +/* + * Class: jtuntap_TunTap + * Method: openTun + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_openTun(JNIEnv *env, jobject this) { + struct ifreq ifr; + int fd; + + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { + printf("error: open\n"); + return 1; + } + + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + + if (ioctl(fd, TUNSETIFF, (void*)&ifr) < 0) { + close(fd); + printf("error: ioctl\n"); + return 1; + } + + setFdDev(env, this, fd, ifr.ifr_name); + + return 0; +} + +/* + * Class: jtuntap_TunTap + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_close(JNIEnv *env, jobject this) { + close(getFd(env, this)); +} + +/* + * Class: jtuntap_TunTap + * Method: write + * Signature: ([BI)V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_write(JNIEnv *env, jobject this, jbyteArray jb, jint len) { + int fd; + jbyte *b; + + fd = getFd(env, this); + b = (*env)->GetByteArrayElements(env, jb, NULL); + + write(fd, b, len); + + (*env)->ReleaseByteArrayElements(env, jb, b, JNI_ABORT); +} + +/* + * Class: jtuntap_TunTap + * Method: read + * Signature: ([B)I + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_read(JNIEnv *env, jobject this, jbyteArray jb) { + int fd; + jbyte *b; + int len; + + fd = getFd(env, this); + b = (*env)->GetByteArrayElements(env, jb, NULL); + + len = read(fd, b, (*env)->GetArrayLength(env, jb)); + + (*env)->ReleaseByteArrayElements(env, jb, b, 0); + return len; +} diff --git a/native/tapLinux/org_p2pvpn_tuntap_TunTapLinux.h b/native/tapLinux/org_p2pvpn_tuntap_TunTapLinux.h new file mode 100644 index 0000000..8743f07 --- /dev/null +++ b/native/tapLinux/org_p2pvpn_tuntap_TunTapLinux.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_p2pvpn_tuntap_TunTapLinux */ + +#ifndef _Included_org_p2pvpn_tuntap_TunTapLinux +#define _Included_org_p2pvpn_tuntap_TunTapLinux +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_p2pvpn_tuntap_TunTapLinux + * Method: openTun + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_openTun + (JNIEnv *, jobject); + +/* + * Class: org_p2pvpn_tuntap_TunTapLinux + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_close + (JNIEnv *, jobject); + +/* + * Class: org_p2pvpn_tuntap_TunTapLinux + * Method: write + * Signature: ([BI)V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_write + (JNIEnv *, jobject, jbyteArray, jint); + +/* + * Class: org_p2pvpn_tuntap_TunTapLinux + * Method: read + * Signature: ([B)I + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapLinux_read + (JNIEnv *, jobject, jbyteArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/tapWindows/Makefile b/native/tapWindows/Makefile new file mode 100644 index 0000000..acd23c3 --- /dev/null +++ b/native/tapWindows/Makefile @@ -0,0 +1,92 @@ +# +# There exist several targets which are by default empty and which can be +# used for execution of your targets. These targets are usually executed +# before and after some main targets. They are: +# +# .build-pre: called before 'build' target +# .build-post: called after 'build' target +# .clean-pre: called before 'clean' target +# .clean-post: called after 'clean' target +# .clobber-pre: called before 'clobber' target +# .clobber-post: called after 'clobber' target +# .all-pre: called before 'all' target +# .all-post: called after 'all' target +# .help-pre: called before 'help' target +# .help-post: called after 'help' target +# +# Targets beginning with '.' are not intended to be called on their own. +# +# Main targets can be executed directly, and they are: +# +# build build a specific configuration +# clean remove built files from a configuration +# clobber remove all built files +# all build all configurations +# help print help mesage +# +# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and +# .help-impl are implemented in nbproject/makefile-impl.mk. +# +# NOCDDL + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib + + +# build +build: .build-pre .build-impl .build-post + +.build-pre: +# Add your pre 'build' code here... + +.build-post: +# Add your post 'build' code here... + + +# clean +clean: .clean-pre .clean-impl .clean-post + +.clean-pre: +# Add your pre 'clean' code here... + +.clean-post: +# Add your post 'clean' code here... + + +# clobber +clobber: .clobber-pre .clobber-impl .clobber-post + +.clobber-pre: +# Add your pre 'clobber' code here... + +.clobber-post: +# Add your post 'clobber' code here... + + +# all +all: .all-pre .all-impl .all-post + +.all-pre: +# Add your pre 'all' code here... + +.all-post: +# Add your post 'all' code here... + + +# help +help: .help-pre .help-impl .help-post + +.help-pre: +# Add your pre 'help' code here... + +.help-post: +# Add your post 'help' code here... + + + +# include project implementation makefile +include nbproject/Makefile-impl.mk diff --git a/native/tapWindows/nbproject/Makefile-Debug.mk b/native/tapWindows/nbproject/Makefile-Debug.mk new file mode 100644 index 0000000..2ac4847 --- /dev/null +++ b/native/tapWindows/nbproject/Makefile-Debug.mk @@ -0,0 +1,63 @@ +# +# Gererated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc.exe +CCC=g++.exe +CXX=g++.exe +FC= + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=build/Debug/Cygwin-Windows + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapWindows.o + +# C Compiler Flags +CFLAGS=-mno-cygwin -Wl,--add-stdcall-alias -shared -m32 + +# CC Compiler Flags +CCFLAGS= +CXXFLAGS= + +# Fortran Compiler Flags +FFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS= + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} dist/Debug/Cygwin-Windows/libTunTapWindows.dll + +dist/Debug/Cygwin-Windows/libTunTapWindows.dll: ${OBJECTFILES} + ${MKDIR} -p dist/Debug/Cygwin-Windows + ${LINK.c} -mno-cygwin -shared -o dist/Debug/Cygwin-Windows/libTunTapWindows.dll -fPIC ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/org_p2pvpn_tuntap_TunTapWindows.o: org_p2pvpn_tuntap_TunTapWindows.c + ${MKDIR} -p ${OBJECTDIR} + $(COMPILE.c) -g -IC\:/Programme/Java/jdk1.6.0_07/include -IC\:/Programme/Java/jdk1.6.0_07/include/win32 -fPIC -o ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapWindows.o org_p2pvpn_tuntap_TunTapWindows.c + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: + ${RM} -r build/Debug + ${RM} dist/Debug/Cygwin-Windows/libTunTapWindows.dll + +# Subprojects +.clean-subprojects: diff --git a/native/tapWindows/nbproject/Makefile-Release.mk b/native/tapWindows/nbproject/Makefile-Release.mk new file mode 100644 index 0000000..1fd512b --- /dev/null +++ b/native/tapWindows/nbproject/Makefile-Release.mk @@ -0,0 +1,63 @@ +# +# Gererated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc.exe +CCC=g++.exe +CXX=g++.exe +FC= + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=build/Release/Cygwin-Windows + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapWindows.o + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS= +CXXFLAGS= + +# Fortran Compiler Flags +FFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS= + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} dist/Release/Cygwin-Windows/libtrunk.dll + +dist/Release/Cygwin-Windows/libtrunk.dll: ${OBJECTFILES} + ${MKDIR} -p dist/Release/Cygwin-Windows + ${LINK.c} -mno-cygwin -shared -o dist/Release/Cygwin-Windows/libtrunk.dll -fPIC ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/org_p2pvpn_tuntap_TunTapWindows.o: org_p2pvpn_tuntap_TunTapWindows.c + ${MKDIR} -p ${OBJECTDIR} + $(COMPILE.c) -O2 -fPIC -o ${OBJECTDIR}/org_p2pvpn_tuntap_TunTapWindows.o org_p2pvpn_tuntap_TunTapWindows.c + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: + ${RM} -r build/Release + ${RM} dist/Release/Cygwin-Windows/libtrunk.dll + +# Subprojects +.clean-subprojects: diff --git a/native/tapWindows/nbproject/Makefile-impl.mk b/native/tapWindows/nbproject/Makefile-impl.mk new file mode 100644 index 0000000..2674c7c --- /dev/null +++ b/native/tapWindows/nbproject/Makefile-impl.mk @@ -0,0 +1,111 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a pre- and a post- target defined where you can add customization code. +# +# This makefile implements macros and targets common to all configurations. +# +# NOCDDL + + +# Building and Cleaning subprojects are done by default, but can be controlled with the SUB +# macro. If SUB=no, subprojects will not be built or cleaned. The following macro +# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf +# and .clean-reqprojects-conf unless SUB has the value 'no' +SUB_no=NO +SUBPROJECTS=${SUB_${SUB}} +BUILD_SUBPROJECTS_=.build-subprojects +BUILD_SUBPROJECTS_NO= +BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} +CLEAN_SUBPROJECTS_=.clean-subprojects +CLEAN_SUBPROJECTS_NO= +CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} + + +# Project Name +PROJECTNAME=trunk + +# Active Configuration +DEFAULTCONF=Debug +CONF=${DEFAULTCONF} + +# All Configurations +ALLCONFS=Debug Release + + +# build +.build-impl: .validate-impl + @#echo "=> Running $@... Configuration=$(CONF)" + ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf + + +# clean +.clean-impl: .validate-impl + @#echo "=> Running $@... Configuration=$(CONF)" + ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf + + +# clobber +.clobber-impl: + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + ${MAKE} -f nbproject/Makefile-$${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf; \ + done + +# all +.all-impl: + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + ${MAKE} -f nbproject/Makefile-$${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf; \ + done + + +# configuration validation +.validate-impl: + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + echo ""; \ + echo "Error: can not find the makefile for configuration '${CONF}' in project ${PROJECTNAME}"; \ + echo "See 'make help' for details."; \ + echo "Current directory: " `pwd`; \ + echo ""; \ + fi + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + exit 1; \ + fi + + +# help +.help-impl: + @echo "This makefile supports the following configurations:" + @echo " ${ALLCONFS}" + @echo "" + @echo "and the following targets:" + @echo " build (default target)" + @echo " clean" + @echo " clobber" + @echo " all" + @echo " help" + @echo "" + @echo "Makefile Usage:" + @echo " make [CONF=] [SUB=no] build" + @echo " make [CONF=] [SUB=no] clean" + @echo " make [SUB=no] clobber" + @echo " make [SUB=no] all" + @echo " make help" + @echo "" + @echo "Target 'build' will build a specific configuration and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'clean' will clean a specific configuration and, unless 'SUB=no'," + @echo " also clean subprojects." + @echo "Target 'clobber' will remove all built files from all configurations and," + @echo " unless 'SUB=no', also from subprojects." + @echo "Target 'all' will will build all configurations and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'help' prints this message." + @echo "" + diff --git a/native/tapWindows/nbproject/configurations.xml b/native/tapWindows/nbproject/configurations.xml new file mode 100644 index 0000000..385a33b --- /dev/null +++ b/native/tapWindows/nbproject/configurations.xml @@ -0,0 +1,81 @@ + + + + + org_p2pvpn_tuntap_TunTapWindows.h + + + + + org_p2pvpn_tuntap_TunTapWindows.c + + + Makefile + + + UTF-8 + Makefile + + + + Cygwin|Cygwin + 3 + + + + + C:/Programme/Java/jdk1.6.0_07/include + C:/Programme/Java/jdk1.6.0_07/include/win32 + + -mno-cygwin -Wl,--add-stdcall-alias -shared -m32 + + + dist/Debug/Cygwin-Windows/libTunTapWindows.dll + + + + + + 0 + + + 3 + + + + + Cygwin|Cygwin + 3 + + + + 5 + + + 5 + + + 5 + + + + + + + + 0 + + + 3 + + + + diff --git a/native/tapWindows/nbproject/private/configurations.xml b/native/tapWindows/nbproject/private/configurations.xml new file mode 100644 index 0000000..9ecfcaa --- /dev/null +++ b/native/tapWindows/nbproject/private/configurations.xml @@ -0,0 +1,37 @@ + + + Makefile + 0 + + + + gdb + 10 + + + + + true + 0 + 0 + + + + + + + gdb + 10 + + + + + true + 0 + 0 + + + + + + diff --git a/native/tapWindows/nbproject/private/private.properties b/native/tapWindows/nbproject/private/private.properties new file mode 100644 index 0000000..e69de29 diff --git a/native/tapWindows/nbproject/private/private.xml b/native/tapWindows/nbproject/private/private.xml new file mode 100644 index 0000000..cc2c0e5 --- /dev/null +++ b/native/tapWindows/nbproject/private/private.xml @@ -0,0 +1,4 @@ + + + + diff --git a/native/tapWindows/nbproject/project.properties b/native/tapWindows/nbproject/project.properties new file mode 100644 index 0000000..e69de29 diff --git a/native/tapWindows/nbproject/project.xml b/native/tapWindows/nbproject/project.xml new file mode 100644 index 0000000..fb9fe62 --- /dev/null +++ b/native/tapWindows/nbproject/project.xml @@ -0,0 +1,11 @@ + + + org.netbeans.modules.cnd.makeproject + + + tapWindows + 0 + + + + diff --git a/native/tapWindows/org_p2pvpn_tuntap_TunTapWindows.c b/native/tapWindows/org_p2pvpn_tuntap_TunTapWindows.c new file mode 100644 index 0000000..c8ac2c7 --- /dev/null +++ b/native/tapWindows/org_p2pvpn_tuntap_TunTapWindows.c @@ -0,0 +1,279 @@ +/* + Copyright 2008 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include "org_p2pvpn_tuntap_TunTapWindows.h" + + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" +#define TAP_COMPONENT_ID_PREFIX "tap" + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define TAPSUFFIX ".tap" + +#define TAP_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) + +typedef struct { + HANDLE fd; + HANDLE read_event; + HANDLE write_event; + OVERLAPPED read_overlapped; + OVERLAPPED write_overlapped; +} TapData; + +// return: error? +int findTapDevice(char *deviceID, int deviceIDLen, char *deviceName, int deviceNameLen, int skip) { + HKEY adapterKey; + int i; + LONG status; + DWORD len; + char keyI[1024]; + char keyName[1024]; + HKEY key; + + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &adapterKey); + + if (status != ERROR_SUCCESS) { + printf("Could not open key '%s'!\n", ADAPTER_KEY); + return 1; + } + + strncpy(deviceID, "", deviceIDLen); + + for (i=0; + deviceID[0]=='\0' && + ERROR_SUCCESS==RegEnumKey(adapterKey, i, keyI, sizeof(keyI)); + i++) { + char componentId[256]; + + snprintf(keyName, sizeof(keyName), "%s\\%s", ADAPTER_KEY, keyI); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key); + if (status != ERROR_SUCCESS) { + printf("Could not open key '%s'!\n", keyName); + return 1; + } + + len = sizeof(componentId); + status=RegQueryValueEx(key, "ComponentId", NULL, NULL, componentId, &len); + if (status == ERROR_SUCCESS && + strncmp(componentId, TAP_COMPONENT_ID_PREFIX, strlen(TAP_COMPONENT_ID_PREFIX))==0) { + if (skip<1) { + len = deviceIDLen; + RegQueryValueEx(key, "NetCfgInstanceId", NULL, NULL, deviceID, &len); + } else { + skip--; + } + } + + RegCloseKey(key); + } + + RegCloseKey(adapterKey); + + if (deviceID[0]==0) return 1; + + snprintf(keyName, sizeof(keyName), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, deviceID); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key); + if (status!=ERROR_SUCCESS) return 1; + + len = deviceNameLen; + status=RegQueryValueEx(key, "Name", NULL, NULL, deviceName, &len); + RegCloseKey(key); + if (status!=ERROR_SUCCESS) return 1; + + return 0; +} + +void setTapDataDev(JNIEnv *env, jobject this, TapData *tapData, char* dev) { + jfieldID jfd, jdev; + jclass jclass; + jstring jstr; + + jclass = (*env)->GetObjectClass(env, this); + + jfd = (*env)->GetFieldID(env, jclass, "cPtr", "J"); + (*env)->SetLongField(env, this, jfd , (jlong)tapData); + + jstr = (*env)->NewStringUTF(env, dev); + jdev = (*env)->GetFieldID(env, jclass, "dev", "Ljava/lang/String;"); + (*env)->SetObjectField(env, this, jdev , jstr); +} + +TapData *getTapData(JNIEnv *env, jobject this) { + jfieldID jfd; + jclass jclass; + + jclass = (*env)->GetObjectClass(env, this); + + jfd = (*env)->GetFieldID(env, jclass, "cPtr", "J"); + return (TapData*)((*env)->GetLongField(env, this, jfd)); +} + +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: openTun + * Signature: ()I + * + * return: 1: not TAP found, 2: could not open TAP + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_openTun + (JNIEnv * env, jobject this) { + char deviceId[256]; + char deviceName[256]; + char tapPath[256]; + TapData *tapData; + unsigned long len = 0; + int status; + int skip = 0; + + tapData = malloc(sizeof(TapData)); + + do { + if (findTapDevice(deviceId, sizeof(deviceId), deviceName, sizeof(deviceName), skip)) { + printf("Could not find a TAP interface\n", tapPath); + return skip==0 ? 1 : 2; // TODO + } + printf("deviceID: '%s'\n", deviceId); + printf("deviceName: '%s'\n", deviceName); + + snprintf(tapPath, sizeof(tapPath), "%s%s%s", USERMODEDEVICEDIR, deviceId, TAPSUFFIX); + + tapData->fd = CreateFile( + tapPath, + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 ); + + if (tapData->fd == INVALID_HANDLE_VALUE) { + printf("Could not open '%s'!\n", tapPath); + skip++; + } + } while (tapData->fd == INVALID_HANDLE_VALUE); + + status = TRUE; + DeviceIoControl(tapData->fd, TAP_IOCTL_SET_MEDIA_STATUS, + &status, sizeof (status), + &status, sizeof (status), &len, NULL); + + tapData->read_event = CreateEvent(NULL, FALSE, FALSE, NULL); + tapData->write_event = CreateEvent(NULL, FALSE, FALSE, NULL); + + tapData->read_overlapped.Offset = 0; + tapData->read_overlapped.OffsetHigh = 0; + tapData->read_overlapped.hEvent = tapData->read_event; + + tapData->write_overlapped.Offset = 0; + tapData->write_overlapped.OffsetHigh = 0; + tapData->write_overlapped.hEvent = tapData->write_event; + + setTapDataDev(env, this, tapData, deviceName); + + return 0; +} + +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_close + (JNIEnv *env , jobject this) { + TapData *tapData; + + tapData = getTapData(env, this); + CloseHandle(tapData->fd); + free(tapData); +} + +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: write + * Signature: ([BI)V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_write + (JNIEnv *env , jobject this, jbyteArray jb, jint len) { + TapData *tapData; + jbyte *b; + DWORD written; + BOOL result; + + tapData = getTapData(env, this); + b = (*env)->GetByteArrayElements(env, jb, NULL); + + result = GetOverlappedResult(tapData->fd, &tapData->write_overlapped, + &written, FALSE); + + if (!result && GetLastError() == ERROR_IO_INCOMPLETE) + WaitForSingleObject(tapData->write_event, INFINITE); + + WriteFile(tapData->fd, b, len, &written, &tapData->write_overlapped); + + (*env)->ReleaseByteArrayElements(env, jb, b, JNI_ABORT); +} + +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: read + * Signature: ([B)I + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_read + (JNIEnv *env, jobject this, jbyteArray jb) { + TapData *tapData; + jbyte *b; + DWORD len; + BOOL result; + + tapData = getTapData(env, this); + b = (*env)->GetByteArrayElements(env, jb, NULL); + + result = ReadFile(tapData->fd, b, (*env)->GetArrayLength(env, jb), &len, &tapData->read_overlapped); + + if (!result) { + if (GetLastError() == ERROR_IO_PENDING) { + WaitForSingleObject(tapData->read_event, INFINITE); + GetOverlappedResult(tapData->fd, &tapData->read_overlapped, &len, FALSE); + } + } + + (*env)->ReleaseByteArrayElements(env, jb, b, 0); + + return len; +} diff --git a/native/tapWindows/org_p2pvpn_tuntap_TunTapWindows.h b/native/tapWindows/org_p2pvpn_tuntap_TunTapWindows.h new file mode 100644 index 0000000..030f2a3 --- /dev/null +++ b/native/tapWindows/org_p2pvpn_tuntap_TunTapWindows.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_p2pvpn_tuntap_TunTapWindows */ + +#ifndef _Included_org_p2pvpn_tuntap_TunTapWindows +#define _Included_org_p2pvpn_tuntap_TunTapWindows +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: openTun + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_openTun + (JNIEnv *, jobject); + +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_close + (JNIEnv *, jobject); + +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: write + * Signature: ([BI)V + */ +JNIEXPORT void JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_write + (JNIEnv *, jobject, jbyteArray, jint); + +/* + * Class: org_p2pvpn_tuntap_TunTapWindows + * Method: read + * Signature: ([B)I + */ +JNIEXPORT jint JNICALL Java_org_p2pvpn_tuntap_TunTapWindows_read + (JNIEnv *, jobject, jbyteArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..e714650 --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,898 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.resources.dir + Must set src.clib.dir + Must set src.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..b4a9805 --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=8a1a520a +build.xml.script.CRC32=18fa743c +build.xml.stylesheet.CRC32=28e38971@1.38.2.45 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=60833d52 +nbproject/build-impl.xml.script.CRC32=033dd344 +nbproject/build-impl.xml.stylesheet.CRC32=f33e10ff@1.38.2.45 diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..366b2b2 --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,74 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=P2PVPN +application.vendor=nerv +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/P2PVPN.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.5 +javac.target=1.5 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class= +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.clib.dir=clib +src.resources.dir=resources +src.src.dir=src diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..81300e4 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + P2PVPN + + + + + + + + + diff --git a/resources/images/P2PVPN-32.png b/resources/images/P2PVPN-32.png new file mode 100644 index 0000000..e818df7 Binary files /dev/null and b/resources/images/P2PVPN-32.png differ diff --git a/resources/images/P2PVPN.svg b/resources/images/P2PVPN.svg new file mode 100644 index 0000000..2e35e6e --- /dev/null +++ b/resources/images/P2PVPN.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/accept.png b/resources/images/accept.png new file mode 100644 index 0000000..924de54 Binary files /dev/null and b/resources/images/accept.png differ diff --git a/resources/images/accept.svg b/resources/images/accept.svg new file mode 100644 index 0000000..47cf76d --- /dev/null +++ b/resources/images/accept.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/resources/images/chat.png b/resources/images/chat.png new file mode 100644 index 0000000..686d81a Binary files /dev/null and b/resources/images/chat.png differ diff --git a/resources/images/chat.svg b/resources/images/chat.svg new file mode 100644 index 0000000..5ffba1d --- /dev/null +++ b/resources/images/chat.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/resources/images/chat_bla.png b/resources/images/chat_bla.png new file mode 100644 index 0000000..4c9239b Binary files /dev/null and b/resources/images/chat_bla.png differ diff --git a/resources/images/chat_bla.svg b/resources/images/chat_bla.svg new file mode 100644 index 0000000..84eb6b9 --- /dev/null +++ b/resources/images/chat_bla.svg @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/direct.png b/resources/images/direct.png new file mode 100644 index 0000000..bca91c8 Binary files /dev/null and b/resources/images/direct.png differ diff --git a/resources/images/direct.svg b/resources/images/direct.svg new file mode 100644 index 0000000..46e0e34 --- /dev/null +++ b/resources/images/direct.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/resources/images/indirect.png b/resources/images/indirect.png new file mode 100644 index 0000000..d58c989 Binary files /dev/null and b/resources/images/indirect.png differ diff --git a/resources/images/indirect.svg b/resources/images/indirect.svg new file mode 100644 index 0000000..d1f7ef3 --- /dev/null +++ b/resources/images/indirect.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/resources/images/info.png b/resources/images/info.png new file mode 100644 index 0000000..b271b28 Binary files /dev/null and b/resources/images/info.png differ diff --git a/resources/images/info.svg b/resources/images/info.svg new file mode 100644 index 0000000..1b2be50 --- /dev/null +++ b/resources/images/info.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/resources/images/invite.png b/resources/images/invite.png new file mode 100644 index 0000000..61b327e Binary files /dev/null and b/resources/images/invite.png differ diff --git a/resources/images/invite.svg b/resources/images/invite.svg new file mode 100644 index 0000000..8aa3ff3 --- /dev/null +++ b/resources/images/invite.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/resources/images/new.png b/resources/images/new.png new file mode 100644 index 0000000..3b0ff35 Binary files /dev/null and b/resources/images/new.png differ diff --git a/resources/images/new.svg b/resources/images/new.svg new file mode 100644 index 0000000..5321ca9 --- /dev/null +++ b/resources/images/new.svg @@ -0,0 +1,114 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/options.png b/resources/images/options.png new file mode 100644 index 0000000..1bf2655 Binary files /dev/null and b/resources/images/options.png differ diff --git a/resources/images/options.svg b/resources/images/options.svg new file mode 100644 index 0000000..316d289 --- /dev/null +++ b/resources/images/options.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/org/p2pvpn/Main.java b/src/org/p2pvpn/Main.java new file mode 100644 index 0000000..aacf62c --- /dev/null +++ b/src/org/p2pvpn/Main.java @@ -0,0 +1,81 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + + +/* + * TODO Linux64, Windows64, Mac + * + */ + package org.p2pvpn; + +import java.io.FileInputStream; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.UIManager; +import org.p2pvpn.gui.MainWindow; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.VPNConnector; +import org.p2pvpn.tools.AdvProperties; + + +/** + * This is the main class of P2PVPN. Depending on the commandline arguments + * the GUI gets startet or not. + * + * @author Wolfgang Ginolas + */ +public class Main { + + /** + * Start P2PVPN. + * @param args the parameters + */ + public static void main(String[] args) { + if (args.length == 5) { + try { + AdvProperties accessCfg = new AdvProperties(); + accessCfg.load(new FileInputStream(args[0])); + + ConnectionManager cm = new ConnectionManager(accessCfg, Integer.parseInt(args[2])); + + if (!args[3].equals("none")) { + cm.getRouter().setLocalPeerInfo("vpn.ip", args[3]); + VPNConnector vpnc = VPNConnector.getVPNConnector(); + vpnc.setRouter(cm.getRouter()); + vpnc.getTunTap().setIP(args[3], args[4]); + } + cm.getRouter().setLocalPeerInfo("name", args[1]); + cm.addIPs(accessCfg); + } catch (Exception exception) { + Logger.getLogger("").log(Level.SEVERE, "Error during Startup", exception); + System.exit(1); + } + } else { + try { + UIManager.setLookAndFeel( + UIManager.getSystemLookAndFeelClassName()); + } catch (Exception ex) { + Logger.getLogger("").log(Level.INFO, "Unable to load native look and feel", ex); + } + //new PeerConfig().setVisible(true); + new MainWindow().setVisible(true); + } + } + +} diff --git a/src/org/p2pvpn/gui/AcceptWindow.form b/src/org/p2pvpn/gui/AcceptWindow.form new file mode 100644 index 0000000..30e008c --- /dev/null +++ b/src/org/p2pvpn/gui/AcceptWindow.form @@ -0,0 +1,125 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/p2pvpn/gui/AcceptWindow.java b/src/org/p2pvpn/gui/AcceptWindow.java new file mode 100644 index 0000000..67c8883 --- /dev/null +++ b/src/org/p2pvpn/gui/AcceptWindow.java @@ -0,0 +1,262 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.security.PublicKey; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPopupMenu; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.p2pvpn.tools.AdvProperties; +import org.p2pvpn.tools.CryptoUtils; + +/** + * This class implements the window which is opened, when the user + * wants ti acceppt an invitation. + * + * @author Wolfgang Ginolas + */ +public class AcceptWindow extends javax.swing.JDialog implements DocumentListener { + + MainControl mainControl; + JFileChooser fileChooser; + + /** Creates new form AcceptWindow + * @param parent the parent window + * @param mainControl the MainControl object + */ + public AcceptWindow(java.awt.Frame parent, MainControl mainControl) { + super(parent, true); + setLocationByPlatform(true); + initComponents(); + try { + URL url = InfoWindow.class.getClassLoader().getResource("resources/images/accept.png"); + setIconImage(new ImageIcon(url).getImage()); + } catch(Throwable e) {} + this.mainControl = mainControl; + fileChooser = new JFileChooser(); + txtInvitation.getDocument().addDocumentListener(this); + btnOK.setEnabled(false); + + JPopupMenu menu = new JPopupMenu(); + JMenuItem mitem = new JMenuItem("Paste"); + mitem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + paste(); + } + }); + menu.add(mitem); + txtInvitation.setComponentPopupMenu(menu); + } + + /** + * Copy the text in the clipbord into the TextArea. + */ + private void paste() { + Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); + boolean hasText = c!=null && c.isDataFlavorAvailable(DataFlavor.stringFlavor); + if (hasText) { + try { + txtInvitation.setText((String) c.getData(DataFlavor.stringFlavor)); + } catch (UnsupportedFlavorException ex) { + Logger.getLogger("").log(Level.WARNING, null, ex); + } catch (IOException ex) { + Logger.getLogger("").log(Level.WARNING, null, ex); + } + } + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + btnCancel = new javax.swing.JButton(); + btnOK = new javax.swing.JButton(); + jPanel1 = new javax.swing.JPanel(); + scrollInvitation = new javax.swing.JScrollPane(); + txtInvitation = new javax.swing.JTextArea(); + btnLoad = new javax.swing.JButton(); + + setTitle("Accept an Invitation"); + + btnCancel.setText("Cancel"); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); + + btnOK.setText("OK"); + btnOK.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOKActionPerformed(evt); + } + }); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Invitation")); + + txtInvitation.setColumns(20); + txtInvitation.setFont(new java.awt.Font("DejaVu Sans", 0, 8)); + txtInvitation.setRows(5); + scrollInvitation.setViewportView(txtInvitation); + + btnLoad.setText("Load from File..."); + btnLoad.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnLoadActionPerformed(evt); + } + }); + + org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .add(btnLoad) + .addContainerGap()) + .add(scrollInvitation, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 388, Short.MAX_VALUE) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .add(btnLoad) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(scrollInvitation, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 192, Short.MAX_VALUE)) + ); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .addContainerGap(304, Short.MAX_VALUE) + .add(btnOK) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnCancel) + .addContainerGap()) + .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(btnCancel) + .add(btnOK)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + +private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed + setVisible(false); +}//GEN-LAST:event_btnCancelActionPerformed + +/** + * Accept an invitation. + */ +private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed + AdvProperties inv = new AdvProperties(txtInvitation.getText()); + AdvProperties[] ps = MainControl.calcNetworkAccess(inv); + mainControl.connectToNewNet(ps[0], ps[1]); + setVisible(false); +}//GEN-LAST:event_btnOKActionPerformed + +/** + * Load an invitation from a file. + */ +private void btnLoadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLoadActionPerformed + if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) { + try { + File file = fileChooser.getSelectedFile(); + FileInputStream in = new FileInputStream(file); + + AdvProperties p = new AdvProperties(); + p.load(in); + txtInvitation.setText(p.toString(null, true, true)); + } catch (IOException iOException) { + Logger.getLogger("").log(Level.WARNING, null, iOException); + JOptionPane.showMessageDialog(null, iOException.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } +}//GEN-LAST:event_btnLoadActionPerformed + + /** + * invChanged is called, when the invitation text changed. + */ + private void invChanged() { + try { + AdvProperties p = new AdvProperties(txtInvitation.getText()); + //AdvProperties net = p.filter("network", false); + + PublicKey netKey = CryptoUtils.decodeRSAPublicKey(p.getPropertyBytes("network.publicKey", null)); + //btnOK.setEnabled(net.verify("network.signature", netKey)); + btnOK.setEnabled(true); + } catch (NullPointerException e) { + btnOK.setEnabled(false); + } + } + + public void insertUpdate(DocumentEvent e) { + invChanged(); + } + + public void removeUpdate(DocumentEvent e) { + invChanged(); + } + + public void changedUpdate(DocumentEvent e) { + invChanged(); + } + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnCancel; + private javax.swing.JButton btnLoad; + private javax.swing.JButton btnOK; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane scrollInvitation; + private javax.swing.JTextArea txtInvitation; + // End of variables declaration//GEN-END:variables + +} diff --git a/src/org/p2pvpn/gui/ChatWindow.form b/src/org/p2pvpn/gui/ChatWindow.form new file mode 100644 index 0000000..92223bb --- /dev/null +++ b/src/org/p2pvpn/gui/ChatWindow.form @@ -0,0 +1,61 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/org/p2pvpn/gui/ChatWindow.java b/src/org/p2pvpn/gui/ChatWindow.java new file mode 100644 index 0000000..7204fd3 --- /dev/null +++ b/src/org/p2pvpn/gui/ChatWindow.java @@ -0,0 +1,225 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.awt.event.KeyEvent; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.text.DateFormat; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.ImageIcon; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.InternalPacketListener; +import org.p2pvpn.network.PeerID; +import org.p2pvpn.network.Router; + +/** + * This class implements the chat window, the user cen use to send messages to + * other users. + * @author Wolfgang Ginolas + */ +public class ChatWindow extends javax.swing.JFrame implements InternalPacketListener { + + private MainWindow mainWindow; + private MainControl mainControl; + + /** Creates new form ChatWindow + * @param mainWindow the MainWindow + * @param mainControl the MainControl + */ + public ChatWindow(MainWindow mainWindow, MainControl mainControl) { + setLocationByPlatform(true); + this.mainControl = mainControl; + this.mainWindow = mainWindow; + initComponents(); + try { + URL url = InfoWindow.class.getClassLoader().getResource("resources/images/chat.png"); + setIconImage(new ImageIcon(url).getImage()); + } catch(Throwable e) {} + txtMessages.setEditable(false); + txtSend.requestFocus(); + } + + /** + * Called by MainWindow when the network has changed. + */ + void networkHasChanged() { + ConnectionManager cm = mainControl.getConnectionManager(); + if (cm!=null) { + Router r = cm.getRouter(); + if (r!=null) { + r.addInternalPacketListener(Router.INTERNAL_PORT_CHAT, this); + } + } + + } + + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jScrollPane1 = new javax.swing.JScrollPane(); + txtMessages = new javax.swing.JTextArea(); + txtSend = new javax.swing.JTextField(); + + setTitle("Chat"); + + txtMessages.setColumns(20); + txtMessages.setRows(5); + jScrollPane1.setViewportView(txtMessages); + + txtSend.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyPressed(java.awt.event.KeyEvent evt) { + txtSendKeyPressed(evt); + } + }); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(txtSend, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 267, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(txtSend, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void txtSendKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtSendKeyPressed + // add your handling code here: + if (evt.getKeyCode() == KeyEvent.VK_ENTER) { + sendMessage(); + } + }//GEN-LAST:event_txtSendKeyPressed + + /** + * Send the message the user entered to all other peers. + */ + private void sendMessage() { + String msg = txtSend.getText(); + txtSend.setText(""); + try { + byte[] fromb = mainControl.getConnectionManager().getLocalAddr().getId(); + byte[] msgb = msg.getBytes("UTF-8"); + byte[] packet = new byte[fromb.length + msgb.length]; + System.arraycopy(fromb, 0, packet, 0, fromb.length); + System.arraycopy(msgb, 0, packet, fromb.length, msgb.length); + + ConnectionManager cm = mainControl.getConnectionManager(); + if (cm!=null) { + Router r = cm.getRouter(); + if (r!=null) { + r.sendInternalPacket(null, Router.INTERNAL_PORT_CHAT, packet); + } + } + + writeMessage(mainControl.nameForPeer(mainControl.getConnectionManager().getLocalAddr()), msg); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(ChatWindow.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Write a message into the TextArea + * @param name the name of the user + * @param msg the message + */ + private void writeMessage(String name, String msg) { + String date = DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()); + String line = date+" "+name+": "+msg+"\n"; + if (!isVisible()) { + if (mainControl.isPopupChat()) { + setVisible(true); + } else { + mainWindow.setChatBla(); + } + } + try { + txtMessages.getDocument().insertString(txtMessages.getDocument().getLength(), line, null); + txtMessages.setCaretPosition(txtMessages.getDocument().getLength()); + } catch (BadLocationException ex) { + //Logger.getLogger("").log(Level.SEVERE, null, ex); + } + } + + /** + * Called by the router, when a chat message is received. + * @param router the Router + * @param internalPort the internel port + * @param data the data + */ + public void receiveInternalPacket(Router router, byte internalPort, byte[] data) { + byte[] fromb = new byte[PeerID.getIdLen()]; + byte[] msgb = new byte[data.length - PeerID.getIdLen()]; + System.arraycopy(data, 0, fromb, 0, fromb.length); + System.arraycopy(data, fromb.length, msgb, 0, msgb.length); + + PeerID from = new PeerID(fromb, false); + String msg; + try { + msg = new String(msgb, "UTF-8"); + SwingUtilities.invokeLater(new ThreadsaveWriteMessage(mainControl.nameForPeer(from), msg)); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger("").log(Level.SEVERE, null, ex); + } + } + + /** + * This class is used to write a message in the TextArea in a + * threadsafe way. + */ + private class ThreadsaveWriteMessage implements Runnable { + private String name; + private String msg; + + public ThreadsaveWriteMessage(String name, String msg) { + this.name = name; + this.msg = msg; + } + + public void run() { + writeMessage(name, msg); + } + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTextArea txtMessages; + private javax.swing.JTextField txtSend; + // End of variables declaration//GEN-END:variables + +} diff --git a/src/org/p2pvpn/gui/IPTableModel.java b/src/org/p2pvpn/gui/IPTableModel.java new file mode 100644 index 0000000..9e5add4 --- /dev/null +++ b/src/org/p2pvpn/gui/IPTableModel.java @@ -0,0 +1,149 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.util.Date; +import java.util.Vector; +import javax.swing.SwingUtilities; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.ConnectorListener; +import org.p2pvpn.network.Connector; + +/** + * A TableModel to show a list of known IPs. + * @author wolfgang + */ +public class IPTableModel implements ConnectorListener, TableModel { + + /* + * Table Columns: IP, ID, Added, Source, (Status, )Keep + */ + + private ConnectionManager connectionManager; + private Connector connector; + private Vector listeners; + private Connector.Endpoint[] table; + + /** + * Create a new IPTableModel + * @param connectionManager the ConnectionManager + */ + public IPTableModel(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + connector = connectionManager.getConnector(); + connector.addListener(this); + listeners = new Vector(); + table = connector.getIPs(); + } + + /** + * Called by connector, when the list of ip's changes. + * @param connector the connector + */ + @Override + public void ipListChanged(Connector connector) { + table = connector.getIPs(); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + notifyListeners(); + } + }); + } + + /** + * Notify all TableModelListeners + */ + private void notifyListeners() { + for(TableModelListener l : listeners) { + l.tableChanged(new TableModelEvent(this)); + } + } + + @Override + public void addTableModelListener(TableModelListener l) { + listeners.add(l); + } + + @Override + public Class getColumnClass(int c) { + switch (c) { + case 0: return String.class; + case 1: return String.class; + case 2: return String.class; + case 3: return String.class; + //case 4: return String.class; + case 4: return Boolean.class; + default: return null; + } + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public String getColumnName(int c) { + switch (c) { + case 0: return "IP"; + case 1: return "ID"; + case 2: return "Added"; + case 3: return "Source"; + //case 4: return "Status"; + case 4: return "Keep"; + default: return null; + } + } + + @Override + public int getRowCount() { + return table.length; + } + + @Override + public Object getValueAt(int r, int c) { + switch (c) { + case 0: return table[r]; + case 1: return connector.getIpInfo(table[r]).getPeerID(); + case 2: return new Date(connector.getIpInfo(table[r]).getTimeAdded()); + case 3: return connector.getIpInfo(table[r]).getSource(); + //case 4: return connector.getIpInfo(table[r]).getStatus(); + case 4: return connector.getIpInfo(table[r]).isKeepForEver(); + default: return null; + } + } + + @Override + public boolean isCellEditable(int r, int c) { + return false; + } + + @Override + public void removeTableModelListener(TableModelListener l) { + listeners.remove(l); + } + + @Override + public void setValueAt(Object o, int r, int c) { + } +} diff --git a/src/org/p2pvpn/gui/InfoWindow.form b/src/org/p2pvpn/gui/InfoWindow.form new file mode 100644 index 0000000..931c412 --- /dev/null +++ b/src/org/p2pvpn/gui/InfoWindow.form @@ -0,0 +1,401 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/p2pvpn/gui/InfoWindow.java b/src/org/p2pvpn/gui/InfoWindow.java new file mode 100644 index 0000000..a8e3068 --- /dev/null +++ b/src/org/p2pvpn/gui/InfoWindow.java @@ -0,0 +1,504 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + + +package org.p2pvpn.gui; + +import java.awt.BorderLayout; +import java.net.URL; +import java.util.Map; + +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; +import javax.swing.ImageIcon; +import javax.swing.SwingUtilities; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.text.Document; +import org.p2pvpn.network.PeerID; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.Router; +import org.p2pvpn.network.RoutungTableListener; +import org.p2pvpn.network.UPnPPortForward; +import org.p2pvpn.network.UPnPPortForwardListener; + +/** + * This is an information window which shows many informations about the + * current status od P2PVPN. + * @author Wolfgang Ginolas + */ +public class InfoWindow extends javax.swing.JFrame implements RoutungTableListener, UPnPPortForwardListener { + + private static final int MAX_LOG_LEN = 10*1000; // the max length of the log TextArea + + private ConnectionManager connectionManager; + private MainControl mainControl; + private PeerID addrShown = null; + + private PeerGraph peerGraph; + + /** Creates new form Main + * @param mainControl the MainControl + */ + public InfoWindow(MainControl mainControl) { + this.mainControl = mainControl; + this.connectionManager = null; + setLocationByPlatform(true); + + initComponents(); + + peerGraph = new PeerGraph(); + pnlPeerGraph.setLayout(new BorderLayout()); + pnlPeerGraph.add(peerGraph); + + peerTable1.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent e) { + for(int i=e.getFirstIndex(); i<=e.getLastIndex(); i++) { + if (peerTable1.getSelectionModel().isSelectedIndex(i)) { + peerSelected(i); + break; + } + } + } + }); + try { + URL url = InfoWindow.class.getClassLoader().getResource("resources/images/info.png"); + setIconImage(new ImageIcon(url).getImage()); + } catch(Throwable e) {} + startLogging(); + } + + /** Called by MainControl, when the network has changed. + */ + void networkHasChanged() { + connectionManager = mainControl.getConnectionManager(); + if (connectionManager != null) { + peerTable1.setModel(new PeerTableModel(connectionManager)); + ipTable.setModel(new IPTableModel(connectionManager)); + setLocalInfo( + "ID: "+connectionManager.getLocalAddr()+ + " Port: "+connectionManager.getServerPort()); + connectionManager.getRouter().addTableListener(InfoWindow.this); + //connectionManager.getUPnPPortForward().addListener(Main.this); + } + peerGraph.setConnectionManager(connectionManager); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jTabbedPane1 = new javax.swing.JTabbedPane(); + jSplitPane1 = new javax.swing.JSplitPane(); + jPanel2 = new javax.swing.JPanel(); + jScrollPane3 = new javax.swing.JScrollPane(); + peerInfo = new javax.swing.JTextArea(); + aPanel1 = new javax.swing.JPanel(); + connectBtn1 = new javax.swing.JButton(); + hostConnectText1 = new javax.swing.JTextField(); + localInfo1 = new javax.swing.JLabel(); + jScrollPane4 = new javax.swing.JScrollPane(); + peerTable1 = new javax.swing.JTable(); + jPanel1 = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + ipTable = new javax.swing.JTable(); + pnlPeerGraph = new javax.swing.JPanel(); + jPanel4 = new javax.swing.JPanel(); + jScrollPane5 = new javax.swing.JScrollPane(); + logText = new javax.swing.JTextArea(); + jPanel3 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jLabel3 = new javax.swing.JLabel(); + jLabel4 = new javax.swing.JLabel(); + + setTitle("P2PVPN"); + + jSplitPane1.setDividerLocation(250); + jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + jSplitPane1.setContinuousLayout(true); + + jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Info")); + + peerInfo.setColumns(20); + peerInfo.setEditable(false); + peerInfo.setRows(5); + peerInfo.setText(" "); + jScrollPane3.setViewportView(peerInfo); + + org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .add(jScrollPane3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel2Layout.createSequentialGroup() + .add(jScrollPane3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 151, Short.MAX_VALUE) + .addContainerGap()) + ); + + jSplitPane1.setRightComponent(jPanel2); + + aPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Connections")); + + connectBtn1.setText("Connect To"); + connectBtn1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eventConnectTo(evt); + } + }); + + hostConnectText1.setToolTipText("host:port"); + + localInfo1.setText(" "); + + peerTable1.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + + } + )); + peerTable1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + jScrollPane4.setViewportView(peerTable1); + + org.jdesktop.layout.GroupLayout aPanel1Layout = new org.jdesktop.layout.GroupLayout(aPanel1); + aPanel1.setLayout(aPanel1Layout); + aPanel1Layout.setHorizontalGroup( + aPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(aPanel1Layout.createSequentialGroup() + .add(aPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(aPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(localInfo1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE)) + .add(aPanel1Layout.createSequentialGroup() + .add(12, 12, 12) + .add(connectBtn1) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(hostConnectText1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 422, Short.MAX_VALUE)) + .add(aPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(jScrollPane4, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE))) + .addContainerGap()) + ); + aPanel1Layout.setVerticalGroup( + aPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, aPanel1Layout.createSequentialGroup() + .add(localInfo1) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jScrollPane4, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(aPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(hostConnectText1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(connectBtn1)) + .addContainerGap()) + ); + + jSplitPane1.setLeftComponent(aPanel1); + + jTabbedPane1.addTab("Connections", jSplitPane1); + + ipTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + + } + )); + jScrollPane1.setViewportView(ipTable); + + org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 516, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 421, Short.MAX_VALUE) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Known IPs", jPanel1); + + org.jdesktop.layout.GroupLayout pnlPeerGraphLayout = new org.jdesktop.layout.GroupLayout(pnlPeerGraph); + pnlPeerGraph.setLayout(pnlPeerGraphLayout); + pnlPeerGraphLayout.setHorizontalGroup( + pnlPeerGraphLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 540, Short.MAX_VALUE) + ); + pnlPeerGraphLayout.setVerticalGroup( + pnlPeerGraphLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 445, Short.MAX_VALUE) + ); + + jTabbedPane1.addTab("Peer Graph", pnlPeerGraph); + + logText.setColumns(20); + logText.setRows(5); + jScrollPane5.setViewportView(logText); + + org.jdesktop.layout.GroupLayout jPanel4Layout = new org.jdesktop.layout.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .add(jScrollPane5, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 516, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .add(jScrollPane5, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 421, Short.MAX_VALUE) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Log", jPanel4); + + jLabel1.setFont(new java.awt.Font("DejaVu Sans", 0, 24)); + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel1.setText("P2PVPN"); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel2.setText("0.7"); + + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel3.setText("11. July 2009"); + + jLabel4.setText("P2PVPN Copyright (C) 2008, 2009 Wolfgang Ginolas
\nThis program comes with ABSOLUTELY NO WARRANTY;
\nThis is free software, and you are welcome to redistribute it
\nunder certain conditions.\n"); + + org.jdesktop.layout.GroupLayout jPanel3Layout = new org.jdesktop.layout.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jLabel2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 516, Short.MAX_VALUE) + .add(jLabel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 516, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabel3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 516, Short.MAX_VALUE) + .add(jLabel4)) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .add(jLabel1) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel2) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel3) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel4) + .addContainerGap(302, Short.MAX_VALUE)) + ); + + jTabbedPane1.addTab("About", jPanel3); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 544, Short.MAX_VALUE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE) + .addContainerGap()) + ); + + pack(); + }//
//GEN-END:initComponents + +private void eventConnectTo(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eventConnectTo + connectionManager.connectTo(hostConnectText1.getText()); +}//GEN-LAST:event_eventConnectTo + + /** + * Called, when the user selects a peer in the peer table. This + * will show the database of the selected peer. + * @param i the selected row + */ + private void peerSelected(int i) { + if (i<0) { + return; + } + + addrShown = ((PeerTableModel)peerTable1.getModel()).getPeerID(i); + tableChanged(null); + } + + /** + * Set information like the PeerID ant the local port which should be + * shown to the user. + * @param s the info + */ + public void setLocalInfo(String s) { + localInfo1.setText(s); + } + + /** + * Called, when the peer-table changes. This will update + * the database shown to the user. + * @param router + */ + public void tableChanged(Router router) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + tableChangedSave(); + } + }); + } + + /** + * Called, when the peer-table changes. This will update + * the database shown to the user. + */ + public void tableChangedSave() { + StringBuffer info = new StringBuffer(); + info.append("Info for "+addrShown+"\n\n"); + Map map = connectionManager.getRouter().getPeerInfo(addrShown); + if (map==null) { + peerInfo.setText(""); + return; + } + + for(Map.Entry e : map.entrySet()) { + info.append(e.getKey()+"="+e.getValue()+"\n"); + } + + peerInfo.setText(info.toString()); + } + + public void upnpChanged(UPnPPortForward upnp) { + /* + InternetGatewayDevice igd = upnp.getIgd(); + if (igd!=null) { + upnpText.setText("Internet Gateway Device: "+igd.getIGDRootDevice().getModelName()+"\n"+ + "External IP: "+upnp.getExternalIP()+"\n" + + "Port mapped: "+upnp.isMapped()+"\n" + + "Error: "+upnp.getError()); + } else { + upnpText.setText("Internet Gateway Device: not found"); + } + */ + } + + /** + * Initialize the logging-tab. + */ + public void startLogging() { + LoggingWriter lt = new LoggingWriter(); + lt.setFormatter(new SimpleFormatter()); + + Logger.getLogger("").addHandler(lt); + } + + /** + * A Logging-Handler which shows all log messages in the log-tab. + */ + class LoggingWriter extends Handler { + + public LoggingWriter() { + super(); + } + + @Override + public void publish(LogRecord r) { + try { + String s = getFormatter().format(r); + Document d = logText.getDocument(); + d.insertString(d.getLength(), s, null); + if (d.getLength() > MAX_LOG_LEN) { + d.remove(0, d.getLength()/2); + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + + + } + + // TODO remove & rename variables + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel aPanel1; + private javax.swing.JButton connectBtn1; + private javax.swing.JTextField hostConnectText1; + private javax.swing.JTable ipTable; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JScrollPane jScrollPane3; + private javax.swing.JScrollPane jScrollPane4; + private javax.swing.JScrollPane jScrollPane5; + private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JTabbedPane jTabbedPane1; + private javax.swing.JLabel localInfo1; + private javax.swing.JTextArea logText; + private javax.swing.JTextArea peerInfo; + private javax.swing.JTable peerTable1; + private javax.swing.JPanel pnlPeerGraph; + // End of variables declaration//GEN-END:variables + + + +} diff --git a/src/org/p2pvpn/gui/InviteWindow.form b/src/org/p2pvpn/gui/InviteWindow.form new file mode 100644 index 0000000..8c65e7a --- /dev/null +++ b/src/org/p2pvpn/gui/InviteWindow.form @@ -0,0 +1,211 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/p2pvpn/gui/InviteWindow.java b/src/org/p2pvpn/gui/InviteWindow.java new file mode 100644 index 0000000..027af5f --- /dev/null +++ b/src/org/p2pvpn/gui/InviteWindow.java @@ -0,0 +1,312 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPopupMenu; +import org.p2pvpn.tools.AdvProperties; + +/** + * This window is shown, when the user wants to invite another persion. + * @author Wolfgang Ginolas + */ +public class InviteWindow extends javax.swing.JDialog implements ClipboardOwner { + + MainControl mainControl; + JFileChooser fileChooser; + + /** Creates new form InviteWindow + * @param parent the parent Frame + * @param mainControl the MainControl + */ + public InviteWindow(java.awt.Frame parent, MainControl mainControl) { + super(parent, true); + setLocationByPlatform(true); + initComponents(); + try { + URL url = InfoWindow.class.getClassLoader().getResource("resources/images/invite.png"); + setIconImage(new ImageIcon(url).getImage()); + } catch(Throwable e) {} + fileChooser = new JFileChooser(); + this.mainControl = mainControl; + + JPopupMenu menu = new JPopupMenu(); + JMenuItem mitem = new JMenuItem("Copy"); + mitem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + copy(); + } + }); + menu.add(mitem); + txtInvitation.setComponentPopupMenu(menu); + } + + /** + * Copy the invitation into the clipboard. + */ + private void copy() { + Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); + c.setContents(new StringSelection(txtInvitation.getText()), this); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + grpDate = new javax.swing.ButtonGroup(); + chkNetwork = new javax.swing.JCheckBox(); + btnGenerate = new javax.swing.JButton(); + jPanel1 = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + txtInvitation = new javax.swing.JTextArea(); + btnSave = new javax.swing.JButton(); + btnClose = new javax.swing.JButton(); + lblDate = new javax.swing.JLabel(); + spnExpiryDate = new javax.swing.JSpinner(); + lblNote = new javax.swing.JLabel(); + radNever = new javax.swing.JRadioButton(); + radDate = new javax.swing.JRadioButton(); + + setTitle("Generate Invitation"); + + chkNetwork.setText("Allow invitation of others"); + chkNetwork.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + chkNetworkItemStateChanged(evt); + } + }); + + btnGenerate.setText("Generate Invitation"); + btnGenerate.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnGenerateActionPerformed(evt); + } + }); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Invitation")); + + txtInvitation.setColumns(20); + txtInvitation.setFont(new java.awt.Font("DejaVu Sans", 0, 8)); + txtInvitation.setRows(5); + jScrollPane1.setViewportView(txtInvitation); + + btnSave.setText("Save to a File..."); + btnSave.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSaveActionPerformed(evt); + } + }); + + org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .add(btnSave) + .addContainerGap()) + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 388, Short.MAX_VALUE) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel1Layout.createSequentialGroup() + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnSave)) + ); + + btnClose.setText("Close"); + btnClose.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCloseActionPerformed(evt); + } + }); + + lblDate.setText("Date of expiry: "); + + spnExpiryDate.setModel(new javax.swing.SpinnerDateModel()); + + lblNote.setText("Make sure to generate a new invitation for every person!"); + + grpDate.add(radNever); + radNever.setSelected(true); + radNever.setText("Never"); + + grpDate.add(radDate); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(chkNetwork) + .addContainerGap(224, Short.MAX_VALUE)) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .addContainerGap(344, Short.MAX_VALUE) + .add(btnClose) + .addContainerGap()) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(lblDate) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .add(radDate) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(spnExpiryDate, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 251, Short.MAX_VALUE)) + .add(radNever)) + .addContainerGap()) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(lblNote) + .addContainerGap(64, Short.MAX_VALUE)) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(btnGenerate) + .addContainerGap(268, Short.MAX_VALUE)) + .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .addContainerGap() + .add(chkNetwork) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(lblDate) + .add(radNever)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(radDate) + .add(spnExpiryDate, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(lblNote) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnGenerate) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnClose) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + +private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed + setVisible(false); +}//GEN-LAST:event_btnCloseActionPerformed + +/** + * Generate an invitation. + */ +private void btnGenerateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGenerateActionPerformed + AdvProperties netCfg = mainControl.getNetworkCfg(); + if (chkNetwork.isSelected()) { + txtInvitation.setText(netCfg.toString(null, false, true)); + } else { + Date date = null; + if (radDate.isSelected()) { + date = (Date)spnExpiryDate.getModel().getValue(); + } + AdvProperties accessCfg = MainControl.genereteAccess(netCfg, date); + txtInvitation.setText(accessCfg.toString(null, false, true)); + } +}//GEN-LAST:event_btnGenerateActionPerformed + +/** + * Save the invitation in a file + */ +private void btnSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSaveActionPerformed + if (JFileChooser.APPROVE_OPTION == fileChooser.showSaveDialog(this)) { + try { + File file = fileChooser.getSelectedFile(); + FileOutputStream out = new FileOutputStream(file); + + AdvProperties p = new AdvProperties(txtInvitation.getText()); + p.store(out, null); + txtInvitation.setText(p.toString(null, true, true)); + } catch (IOException iOException) { + Logger.getLogger("").log(Level.WARNING, null, iOException); + JOptionPane.showMessageDialog(null, iOException.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } +}//GEN-LAST:event_btnSaveActionPerformed + +private void chkNetworkItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkNetworkItemStateChanged + // TODO add your handling code here: + if (chkNetwork.isSelected()) { + lblNote.setVisible(false); + spnExpiryDate.setEnabled(false); + lblDate.setEnabled(false); + radNever.setEnabled(false); + radDate.setEnabled(false); + } else { + lblNote.setVisible(true); + spnExpiryDate.setEnabled(true); + lblDate.setEnabled(true); + radNever.setEnabled(true); + radDate.setEnabled(true); + } +}//GEN-LAST:event_chkNetworkItemStateChanged + + public void lostOwnership(Clipboard arg0, Transferable arg1) { + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnClose; + private javax.swing.JButton btnGenerate; + private javax.swing.JButton btnSave; + private javax.swing.JCheckBox chkNetwork; + private javax.swing.ButtonGroup grpDate; + private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JLabel lblDate; + private javax.swing.JLabel lblNote; + private javax.swing.JRadioButton radDate; + private javax.swing.JRadioButton radNever; + private javax.swing.JSpinner spnExpiryDate; + private javax.swing.JTextArea txtInvitation; + // End of variables declaration//GEN-END:variables + + +} diff --git a/src/org/p2pvpn/gui/MainControl.java b/src/org/p2pvpn/gui/MainControl.java new file mode 100644 index 0000000..5ec3497 --- /dev/null +++ b/src/org/p2pvpn/gui/MainControl.java @@ -0,0 +1,474 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.awt.HeadlessException; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.util.Date; +import java.util.Random; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.Connector; +import org.p2pvpn.network.ConnectorListener; +import org.p2pvpn.network.PeerID; +import org.p2pvpn.network.TCPConnection; +import org.p2pvpn.network.VPNConnector; +import org.p2pvpn.tools.AdvProperties; +import org.p2pvpn.tools.CryptoUtils; +import org.p2pvpn.tuntap.TunTap; +import org.p2pvpn.tools.ProfileManager; + +/** + * This class controls everything regarded to the GUI or storing the settings + * of P2PVPN. + * @author Wolfgang Ginolas + */ +public class MainControl implements ConnectorListener { + private static final String DEFAULT_NET_FILE = "default.net"; + + private AdvProperties networkCfg; // the invitations for the current network + private AdvProperties accessCfg; + + private ConnectionManager connectionManager; + private MainWindow mainWindow; + private TunTap tuntap; + + private int serverPort; // the local port + private String name; // the name of this nide + private double sendLimit, recLimit; // bandwidth limit for this node + private int sendBufferSize; // the size of the send buffer + private boolean tcpFlush; // flush after each packet? + private String ip; // the IP of the virtual network adapter + private boolean popupChat; // should the chat window popup when a message arrives? + + //private Preferences prefs; // used to store all settings + private ProfileManager prefs; + + /** + * Create a new MainControl + * @param mainWindow the MainWindow + */ + public MainControl(MainWindow mainWindow) { + + + ProfileManager profile = new ProfileManager(); + prefs = profile.load("default"); + + tuntap = null; + connectionManager = null; + this.mainWindow = mainWindow; + + serverPort = prefs.getInt("serverPort", 0); + setName(prefs.get("name", "no name")); + String accessStr = prefs.get("access", null); + accessCfg = accessStr==null ? null : new AdvProperties(accessStr); + String netStr = prefs.get("network", null); + networkCfg = netStr==null ? null : new AdvProperties(netStr); + ip = prefs.get("ip", ""); + sendLimit = prefs.getDouble("sendLimit", 0); + recLimit = prefs.getDouble("recLimit", 0); + sendBufferSize = prefs.getInt("sendBufferSize", TCPConnection.DEFAULT_MAX_QUEUE); + tcpFlush = prefs.getBoolean("tcpFlush", TCPConnection.DEFAULT_TCP_FLUSH); + + popupChat = prefs.getBoolean("popupChat", false); + + if (accessCfg == null) loadDefaultNet(); + } + + /** + * Load the default settings. + */ + private void loadDefaultNet() { + try { + InputStream in = MainControl.class.getClassLoader().getResourceAsStream(DEFAULT_NET_FILE); + AdvProperties inv = new AdvProperties(); + inv.load(in); + String netName = inv.getProperty("network.name"); + if (JOptionPane.YES_OPTION == + JOptionPane.showConfirmDialog(null, + "Your P2PVPN is not part of any network.\n" + + "Do you want to join '" + netName + "'?", "Default Network", + JOptionPane.YES_NO_OPTION)) { + AdvProperties[] ps = calcNetworkAccess(inv); + networkCfg = ps[0]; + accessCfg = ps[1]; + generateRandomIP(); + } + } catch (IOException iOException) { + } catch (HeadlessException headlessException) { + } + } + + /** + * Called after initialisation and starts the operation of P2PVPN. + */ + public void start() { + changeNet(false); + } + + /** + * Connect to a network. + * @param networkCfg the network invitation + * @param accessCfg the access initation + */ + public void connectToNewNet(AdvProperties networkCfg, AdvProperties accessCfg) { + this.networkCfg = networkCfg; + this.accessCfg = accessCfg; + + if (accessCfg!=null) generateRandomIP(); + + changeNet(true); + } + + /** + * Create an random IP address for the virtual network adapter. + */ + private void generateRandomIP() { + try { + Random random = new Random(); + InetAddress net = InetAddress.getByName(accessCfg.getProperty("network.ip.network")); + InetAddress subnet = InetAddress.getByName(accessCfg.getProperty("network.ip.subnet")); + + byte[] myIPb = new byte[4]; + byte[] netb = net.getAddress(); + byte[] subnetb = subnet.getAddress(); + + // TODO don't create a broadcast address + for (int i = 0; i < 4; i++) { + myIPb[i] = (byte) (netb[i] ^ ((~subnetb[i]) & (byte)random.nextInt())); + } + + ip = (0xFF & myIPb[0]) + "." + (0xFF & myIPb[1]) + "." + (0xFF & myIPb[2]) + "." + (0xFF & myIPb[3]); + } catch (UnknownHostException ex) { + Logger.getLogger(MainControl.class.getName()).log(Level.SEVERE, null, ex); + assert false; + } + } + + /** + * This is called, when the network has changed. It will setup the new + * network and notify other parts of P2PVPN. + * @param networkChanged was P2PVPN connectet to another network before + * this method was called? + */ + private void changeNet(boolean networkChanged) { + if (connectionManager!=null) connectionManager.close(); + if (accessCfg!=null) { + try { + connectionManager = new ConnectionManager(accessCfg, serverPort); + + try { + VPNConnector vpnc = VPNConnector.getVPNConnector(); + vpnc.setRouter(connectionManager.getRouter()); + tuntap = vpnc.getTunTap(); + setIp(ip); + } catch (Throwable e) { + Logger.getLogger("").log(Level.SEVERE, "", e); + JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + connectionManager.getRouter().setLocalPeerInfo("name", name); + connectionManager.addIPs(accessCfg); + + connectionManager.getConnector().addListener(this); + if (!networkChanged) addStoredIPs(); + + connectionManager.getSendLimit().setBandwidth(sendLimit); + connectionManager.getRecLimit().setBandwidth(recLimit); + connectionManager.setSendBufferSize(sendBufferSize); + connectionManager.setTCPFlush(tcpFlush); + + prefs.put("access", accessCfg.toString()); + if (networkCfg==null) { + prefs.remove("network"); + } else { + prefs.put("network", networkCfg.toString()); + } + prefs.put("ip", ip); + prefsFlush(); + } catch (Throwable e) { + Logger.getLogger("").log(Level.SEVERE, "", e); + JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + System.exit(0); + } + } + mainWindow.networkHasChanged(); + } + + /** + * Add the IPs stored in the Preferences to the known IPs list. + */ + private void addStoredIPs() { + String ipStr = prefs.get("knownIPs", ""); + StringTokenizer ips = new StringTokenizer(ipStr, ";"); + + while (ips.hasMoreTokens()) { + try { + StringTokenizer st = new StringTokenizer(ips.nextToken(), ":"); + String ip = st.nextToken(); + int port = Integer.parseInt(st.nextToken()); + connectionManager.getConnector().addIP(ip, port, null, "stored", "", false); + } catch (NumberFormatException numberFormatException) { + } + } + } + + /** + * Called, when th list of known IPs changes. This method will store + * the list in the Preferences. + * @param c the Connector + */ + public void ipListChanged(Connector c) { + Connector.Endpoint[] es = c.getIPs(); + String ips = ""; + for (int i = 0; i < es.length; i++) { + if (i > 0) { + ips = ips + ";"; + } + ips = ips + es[i].toString(); + } + prefs.put("knownIPs", ips); + prefsFlush(); + } + + + /** + * Return the name of the peer. + * @param peer the peer + * @return the name or "?" when the name is unknown + */ + public String nameForPeer(PeerID peer) { + if (connectionManager==null) return ""; + String name = connectionManager.getRouter().getPeerInfo(peer, "name"); + if (name==null) return "?"; + return name; + } + + /** + * Return a short description for a peer. + * @param peer the peer + * @return the description + */ + public String descriptionForPeer(PeerID peer) { + if (connectionManager==null) return ""; + + StringBuffer result = new StringBuffer(); + + result.append(""); + result.append("Name: "+nameForPeer(peer)); + + String ip = connectionManager.getRouter().getPeerInfo(peer, "vpn.ip"); + if (ip!=null) result.append("
IP: "+ip); + + if (connectionManager.getRouter().isConnectedTo(peer)) { + result.append("
direct connection"); + } else { + if (!connectionManager.getLocalAddr().equals(peer)) { + result.append("
indirect connection"); + } + } + + result.append("
Peer ID: "+peer); + result.append(""); + + return result.toString(); + } + + /** + * Flush the Preferences to disk. + */ + private void prefsFlush() { + + prefs.flush(); + /* + * No need to catch exception, ProfielManager do it now + * + try { + prefs.flush(); + } catch (BackingStoreException ex) { + Logger.getLogger("").log(Level.WARNING, null, ex); + } + * + */ + } + + public ConnectionManager getConnectionManager() { + return connectionManager; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + + if (tuntap!=null) { + tuntap.setIP(ip, accessCfg.getProperty("network.ip.subnet")); + if (connectionManager!=null) { + connectionManager.getRouter().setLocalPeerInfo("vpn.ip", ip); + } + prefs.put("ip", ip); + prefsFlush(); + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + if (connectionManager!=null) { + connectionManager.getRouter().setLocalPeerInfo("name", name); + } + mainWindow.setNodeName(name); + prefs.put("name", name); + prefsFlush(); + } + + public int getServerPort() { + return serverPort; + } + + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + prefs.putInt("serverPort", serverPort); + prefsFlush(); + } + + public AdvProperties getAccessCfg() { + return accessCfg; + } + + public AdvProperties getNetworkCfg() { + return networkCfg; + } + + + /** + * Generate an access invitation from an network invitation. + * @param netCfg the network invitation + * @param date the date of expiry + * @return the acess invitation + */ + public static AdvProperties genereteAccess(AdvProperties netCfg, Date date) { + PrivateKey netPriv = CryptoUtils.decodeRSAPrivateKey( + netCfg.getPropertyBytes("secret.network.privateKey", null)); + + KeyPair accessKp = CryptoUtils.createEncryptionKeyPair(); + + AdvProperties accessCfg = new AdvProperties(); + if (date==null) { + accessCfg.setProperty("access.expiryDate", "none"); + } else { + accessCfg.setProperty("access.expiryDate", ""+date.getTime()); + } + accessCfg.setPropertyBytes("access.publicKey", accessKp.getPublic().getEncoded()); + accessCfg.sign("access.signature", netPriv); + accessCfg.setPropertyBytes("secret.access.privateKey", accessKp.getPrivate().getEncoded()); + + accessCfg.putAll(netCfg.filter("secret", true)); + + return accessCfg; + } + + /** + * Find out the type of the given invitation and return a network/access + * invitation pair. + * @param inv the network invitation + * @return an array with two invitations {net, access}. + */ + public static AdvProperties[] calcNetworkAccess(AdvProperties inv) { + AdvProperties net; + AdvProperties access; + + if (inv.getPropertyBytes("secret.network.privateKey", null)==null) { + net = null; + access = inv; + } else { + net = inv; + access = MainControl.genereteAccess(net, null); + } + + return new AdvProperties[] {net, access}; + } + + public double getRecLimit() { + return recLimit; + } + + public void setRecLimit(double recLimit) { + this.recLimit = recLimit; + if (connectionManager!=null) connectionManager.getRecLimit().setBandwidth(recLimit); + prefs.putDouble("recLimit", recLimit); + prefsFlush(); + } + + public double getSendLimit() { + return sendLimit; + } + + public void setSendLimit(double sendLimit) { + this.sendLimit = sendLimit; + if (connectionManager!=null) connectionManager.getSendLimit().setBandwidth(sendLimit); + prefs.putDouble("sendLimit", sendLimit); + prefsFlush(); + } + + public int getSendBufferSize() { + return sendBufferSize; + } + + public void setSendBufferSize(int sendBufferSize) { + this.sendBufferSize = sendBufferSize; + if (connectionManager!=null) connectionManager.setSendBufferSize(sendBufferSize); + prefs.putInt("sendBufferSize", sendBufferSize); + prefsFlush(); + } + + public boolean isTCPFlush() { + return tcpFlush; + } + + public void setTCPFlush(boolean tcpFlush) { + this.tcpFlush = tcpFlush; + if (connectionManager!=null) connectionManager.setTCPFlush(tcpFlush); + prefs.putBoolean("tcpFlush", tcpFlush); + prefsFlush(); + } + + public boolean isPopupChat() { + return popupChat; + } + + public void setPopupChat(boolean popupChat) { + this.popupChat = popupChat; + prefs.putBoolean("popupChat", popupChat); + prefsFlush(); + } +} diff --git a/src/org/p2pvpn/gui/MainWindow.form b/src/org/p2pvpn/gui/MainWindow.form new file mode 100644 index 0000000..6fee560 --- /dev/null +++ b/src/org/p2pvpn/gui/MainWindow.form @@ -0,0 +1,166 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/p2pvpn/gui/MainWindow.java b/src/org/p2pvpn/gui/MainWindow.java new file mode 100644 index 0000000..65ed92a --- /dev/null +++ b/src/org/p2pvpn/gui/MainWindow.java @@ -0,0 +1,457 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; +import org.p2pvpn.network.PeerID; +import org.p2pvpn.network.Router; +import org.p2pvpn.network.RoutungTableListener; + +/** + * This is the main window of P2PVPN. + * + * @author Wolfgang Ginoas + */ +public class MainWindow extends javax.swing.JFrame implements RoutungTableListener { + + private static final String P2PVPN_IMG = "resources/images/P2PVPN-32.png"; + private static final String CHAT_IMG = "resources/images/chat.png"; + private static final String CHAT_BLA_IMG = "resources/images/chat_bla.png"; + + private MainControl mainControl; // the MainControl + private NewNetwork newNetwork; // the other windows + private OptionWindow optionWindow; + private InviteWindow inviteWindow; + private AcceptWindow acceptWindow; + private ChatWindow chatWindow; + private InfoWindow infoWindow; + + private PeerListModel peerListModel;// model for the peer list + private PeerListCellRenderer peerListCellRenderer; // cell renderer for the peer list + + private TrayIcon trayIcon; // the try icon + + /** Creates new form MainWindow and + * and initializes the MainControl and all the other windows + */ + public MainWindow() { + setLocationByPlatform(true); + peerListModel = new PeerListModel(); + peerListCellRenderer = new PeerListCellRenderer(); + initComponents(); + try { + URL url = InfoWindow.class.getClassLoader().getResource(P2PVPN_IMG); + setIconImage(new ImageIcon(url).getImage()); + } catch(NullPointerException e) {} + + setButtonIcon(btnNewNet, "resources/images/new.png"); + setButtonIcon(btnInvite, "resources/images/invite.png"); + setButtonIcon(btnAccept, "resources/images/accept.png"); + setButtonIcon(btnOptions, "resources/images/options.png"); + setButtonIcon(btnInfo, "resources/images/info.png"); + setButtonIcon(btnChat, CHAT_IMG); + + mainControl = new MainControl(this); + newNetwork = new NewNetwork(this, mainControl); + optionWindow = new OptionWindow(this); + inviteWindow = new InviteWindow(this, mainControl); + acceptWindow = new AcceptWindow(this, mainControl); + chatWindow = new ChatWindow(this, mainControl); + infoWindow = new InfoWindow(mainControl); + + try { + PopupMenu popupMenu = new PopupMenu(); + + MenuItem show = new MenuItem("Show"); + show.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + setVisible(true); + } + }); + popupMenu.add(show); + + MenuItem hide = new MenuItem("Hide"); + hide.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + setVisible(false); + } + }); + popupMenu.add(hide); + popupMenu.addSeparator(); + + MenuItem quit = new MenuItem("Quit"); + quit.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + System.exit(0); + } + }); + popupMenu.add(quit); + + trayIcon = new TrayIcon( + Toolkit.getDefaultToolkit().getImage(InfoWindow.class.getClassLoader().getResource(P2PVPN_IMG)), + "P2PVPN", popupMenu); + trayIcon.setImageAutoSize(true); + + trayIcon.addMouseListener(new MouseAdapter() { + @Override public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + setVisible(!isVisible()); + } + } + }); + + SystemTray.getSystemTray().add(trayIcon); + setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + } catch (Throwable t) { + Logger.getLogger("").log(Level.INFO, "Coult not create Tray-Icon", t); + } + + mainControl.start(); + } + + /** + * Set tht icon for an button + * @param btn the button + * @param path thi icon + */ + private void setButtonIcon(JButton btn, String path) { + try { + btn.setIcon(new ImageIcon(InfoWindow.class.getClassLoader().getResource(path))); + btn.setText(""); + } catch (NullPointerException e) { + System.err.println("could not load "+path); + } + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jToolBar1 = new javax.swing.JToolBar(); + btnNewNet = new javax.swing.JButton(); + btnAccept = new javax.swing.JButton(); + btnInvite = new javax.swing.JButton(); + btnOptions = new javax.swing.JButton(); + btnChat = new javax.swing.JButton(); + jSeparator1 = new javax.swing.JToolBar.Separator(); + lblName = new javax.swing.JLabel(); + jScrollPane1 = new javax.swing.JScrollPane(); + lstPeers = new javax.swing.JList(); + btnInfo = new javax.swing.JButton(); + txtNetwork = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setTitle("P2PVPN"); + + jToolBar1.setFloatable(false); + jToolBar1.setRollover(true); + + btnNewNet.setText("N"); + btnNewNet.setToolTipText("New Network..."); + btnNewNet.setFocusable(false); + btnNewNet.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnNewNet.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnNewNet.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnNewNetActionPerformed(evt); + } + }); + jToolBar1.add(btnNewNet); + + btnAccept.setText("A"); + btnAccept.setToolTipText("Accept Invitation..."); + btnAccept.setFocusable(false); + btnAccept.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnAccept.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnAccept.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnAcceptActionPerformed(evt); + } + }); + jToolBar1.add(btnAccept); + + btnInvite.setText("I"); + btnInvite.setToolTipText("Invite someone..."); + btnInvite.setFocusable(false); + btnInvite.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnInvite.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnInvite.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnInviteActionPerformed(evt); + } + }); + jToolBar1.add(btnInvite); + + btnOptions.setText("O"); + btnOptions.setToolTipText("Options..."); + btnOptions.setFocusable(false); + btnOptions.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnOptions.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnOptions.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOptionsActionPerformed(evt); + } + }); + jToolBar1.add(btnOptions); + + btnChat.setText("C"); + btnChat.setToolTipText("Chat..."); + btnChat.setFocusable(false); + btnChat.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnChat.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnChat.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnChatActionPerformed(evt); + } + }); + jToolBar1.add(btnChat); + jToolBar1.add(jSeparator1); + + lblName.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + lblName.setText("Name"); + jToolBar1.add(lblName); + + lstPeers.setModel(peerListModel); + lstPeers.setCellRenderer(peerListCellRenderer); + lstPeers.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + lstPeersMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + lstPeersMousePressed(evt); + } + }); + jScrollPane1.setViewportView(lstPeers); + + btnInfo.setText("I"); + btnInfo.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnInfoActionPerformed(evt); + } + }); + + txtNetwork.setText("Network"); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jToolBar1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .add(txtNetwork) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 138, Short.MAX_VALUE) + .add(btnInfo)) + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .add(jToolBar1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 25, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 267, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(btnInfo) + .add(txtNetwork))) + ); + + pack(); + }// //GEN-END:initComponents + +private void btnNewNetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewNetActionPerformed + newNetwork.setVisible(true); +}//GEN-LAST:event_btnNewNetActionPerformed + +private void btnInfoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnInfoActionPerformed + infoWindow.setVisible(true); +}//GEN-LAST:event_btnInfoActionPerformed + +/** + * Open the options window. + */ +private void btnOptionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOptionsActionPerformed + optionWindow.setNodeName(mainControl.getName()); + optionWindow.setPort(mainControl.getServerPort()); + optionWindow.setIP(mainControl.getIp()); + optionWindow.setSendLimit(mainControl.getSendLimit()); + optionWindow.setRecLimit(mainControl.getRecLimit()); + optionWindow.setSendBufferSize(mainControl.getSendBufferSize()); + optionWindow.setTCPFlush(mainControl.isTCPFlush()); + optionWindow.setPopupChat(mainControl.isPopupChat()); + optionWindow.setVisible(true); + if (optionWindow.isOk()) { + mainControl.setName(optionWindow.getNodeName()); + mainControl.setServerPort(optionWindow.getPort()); + mainControl.setIp(optionWindow.getIP()); + mainControl.setSendLimit(optionWindow.getSendLimit()); + mainControl.setRecLimit(optionWindow.getRecLimit()); + mainControl.setSendBufferSize(optionWindow.getSendBufferSize()); + mainControl.setTCPFlush(optionWindow.isTCPFlush()); + mainControl.setPopupChat(optionWindow.isPopupChat()); + } +}//GEN-LAST:event_btnOptionsActionPerformed + +private void btnInviteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnInviteActionPerformed + inviteWindow.setVisible(true); +}//GEN-LAST:event_btnInviteActionPerformed + +private void btnAcceptActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAcceptActionPerformed + acceptWindow.setVisible(true); +}//GEN-LAST:event_btnAcceptActionPerformed + +private void btnChatActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnChatActionPerformed + chatWindow.setVisible(true); + setButtonIcon(btnChat, CHAT_IMG); + if (trayIcon!=null) { + trayIcon.setImage(Toolkit.getDefaultToolkit().getImage(InfoWindow.class.getClassLoader().getResource(P2PVPN_IMG))); + } +}//GEN-LAST:event_btnChatActionPerformed + +/** + * Context menu for the peer-list + */ +private void lstPeersMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_lstPeersMousePressed + + JPopupMenu menu = new JPopupMenu(); + if (menu.isPopupTrigger(evt)) { + int i = lstPeers.locationToIndex(evt.getPoint()); + if (i>=0 && mainControl.getConnectionManager()!=null) { + PeerID peer = (PeerID)lstPeers.getModel().getElementAt(i); + String ip = mainControl.getConnectionManager().getRouter().getPeerInfo(peer, "vpn.ip"); + if (ip!=null) { + JMenuItem mitem = new JMenuItem("Copy IP address"); + mitem.addActionListener(new PopupMenuListener(ip)); + menu.add(mitem); + menu.show(evt.getComponent(), evt.getX(), evt.getY()); + } + } + } +}//GEN-LAST:event_lstPeersMousePressed + + void setChatBla() { + setButtonIcon(btnChat, CHAT_BLA_IMG); + if (trayIcon!=null) { + trayIcon.setImage(Toolkit.getDefaultToolkit().getImage(InfoWindow.class.getClassLoader().getResource(CHAT_BLA_IMG))); + } + } + + public void setNodeName(String name) { + lblName.setText(name); + } + + /** + * Called from MeinControl when the network has changed. + */ + public void networkHasChanged() { + btnInvite.setEnabled(mainControl.getNetworkCfg()!=null); + peerListModel.setConnectionManager(mainControl.getConnectionManager()); + peerListCellRenderer.setMainControl(mainControl); + if (mainControl.getConnectionManager()!=null) { + mainControl.getConnectionManager().getRouter().addTableListener(this); + lblName.setToolTipText(null); + tableChanged(mainControl.getConnectionManager().getRouter()); + } + if (mainControl.getAccessCfg()==null) { + txtNetwork.setText("not connected"); + } else { + txtNetwork.setText(mainControl.getAccessCfg().getProperty("network.name", "")); + } + chatWindow.networkHasChanged(); + infoWindow.networkHasChanged(); + } + + /** + * Called when the peer list changes. + * @param router the Router + */ + public void tableChanged(Router router) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + tableChangedSave(); + } + }); + } + + public void tableChangedSave() { + lblName.setToolTipText(mainControl.descriptionForPeer(mainControl.getConnectionManager().getLocalAddr())); + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnAccept; + private javax.swing.JButton btnChat; + private javax.swing.JButton btnInfo; + private javax.swing.JButton btnInvite; + private javax.swing.JButton btnNewNet; + private javax.swing.JButton btnOptions; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JToolBar.Separator jSeparator1; + private javax.swing.JToolBar jToolBar1; + private javax.swing.JLabel lblName; + private javax.swing.JList lstPeers; + private javax.swing.JLabel txtNetwork; + // End of variables declaration//GEN-END:variables + + + /** + * A listener for the peer context menu. + */ + class PopupMenuListener implements ActionListener, ClipboardOwner { + String ip; + + public PopupMenuListener(String ip) { + this.ip = ip; + } + + public void actionPerformed(ActionEvent e) { + Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); + c.setContents(new StringSelection(ip), this); + } + + public void lostOwnership(Clipboard clipboard, Transferable contents) { + } + } +} diff --git a/src/org/p2pvpn/gui/NewNetwork.form b/src/org/p2pvpn/gui/NewNetwork.form new file mode 100644 index 0000000..58bfefa --- /dev/null +++ b/src/org/p2pvpn/gui/NewNetwork.form @@ -0,0 +1,219 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/p2pvpn/gui/NewNetwork.java b/src/org/p2pvpn/gui/NewNetwork.java new file mode 100644 index 0000000..ae809d0 --- /dev/null +++ b/src/org/p2pvpn/gui/NewNetwork.java @@ -0,0 +1,272 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.net.URL; +import java.security.KeyPair; +import java.util.StringTokenizer; +import javax.swing.ImageIcon; +import org.p2pvpn.tools.AdvProperties; +import org.p2pvpn.tools.CryptoUtils; + +/** + * This Windows is opened, when the user wants to create a new network. + * @author Wolfgang Ginolas + */ +public class NewNetwork extends javax.swing.JDialog { + + private MainControl mainControl; + + /** Creates new form NewNetwork + * @param parent the parent window + * @param mainControl the MainControl + */ + public NewNetwork(java.awt.Frame parent, MainControl mainControl) { + super(parent, true); + setLocationByPlatform(true); + initComponents(); + try { + URL url = InfoWindow.class.getClassLoader().getResource("resources/images/new.png"); + setIconImage(new ImageIcon(url).getImage()); + } catch(Throwable e) {} + this.mainControl = mainControl; + + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent e) { + cancel(); + } + }); + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jTabbedPane1 = new javax.swing.JTabbedPane(); + jPanel1 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + txtName = new javax.swing.JTextField(); + jPanel2 = new javax.swing.JPanel(); + jLabel2 = new javax.swing.JLabel(); + jLabel3 = new javax.swing.JLabel(); + jLabel4 = new javax.swing.JLabel(); + txtNetwork = new javax.swing.JTextField(); + txtSubnetMask = new javax.swing.JTextField(); + txtConnectTo = new javax.swing.JTextField(); + jLabel5 = new javax.swing.JLabel(); + txtTracker = new javax.swing.JTextField(); + btnCancel = new javax.swing.JButton(); + btnOK = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + jLabel1.setText("Network Name"); + + org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(jLabel1) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(txtName, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel1) + .add(txtName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(141, Short.MAX_VALUE)) + ); + + jTabbedPane1.addTab("Simple", jPanel1); + + jLabel2.setText("Network"); + + jLabel3.setText("Subnet Mask"); + + jLabel4.setText("Known Hosts"); + + txtNetwork.setText("10.6.0.0"); + + txtSubnetMask.setText("255.255.0.0"); + + txtConnectTo.setToolTipText("host1:port1;host2:port2;..."); + + jLabel5.setText("BitTorrent Tracker"); + + txtTracker.setText("http://tracker.thepiratebay.org:80/announce"); + + org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jLabel5) + .add(jLabel3) + .add(jLabel2) + .add(jLabel4)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(txtNetwork, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE) + .add(txtSubnetMask, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.TRAILING, txtConnectTo, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE) + .add(txtTracker, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel2) + .add(txtNetwork, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel3) + .add(txtSubnetMask, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel4) + .add(txtConnectTo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel5) + .add(txtTracker, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .add(98, 98, 98)) + ); + + jTabbedPane1.addTab("Advanced", jPanel2); + + btnCancel.setText("Cancel"); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); + + btnOK.setText("OK"); + btnOK.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOKActionPerformed(evt); + } + }); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .addContainerGap(298, Short.MAX_VALUE) + .add(btnOK) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnCancel) + .addContainerGap()) + .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 205, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(btnCancel) + .add(btnOK)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + +private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed + cancel(); +}//GEN-LAST:event_btnCancelActionPerformed + +private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed + ok(); +}//GEN-LAST:event_btnOKActionPerformed + + private void cancel() { + setVisible(false); + } + + /** + * The user pressed OK. Create a new network. + */ + private void ok() { + AdvProperties netCfg = new AdvProperties(); + netCfg.setProperty("network.name", txtName.getText()); + netCfg.setProperty("network.ip.network", txtNetwork.getText()); + netCfg.setProperty("network.ip.subnet", txtSubnetMask.getText()); + + StringTokenizer st = new StringTokenizer(txtConnectTo.getText(),";"); + int i = 0; + while (st.hasMoreTokens()) { + netCfg.setProperty("network.bootstrap.connectTo."+i, st.nextToken()); + i++; + } + + if (!"".equals(txtTracker.getText())) { + netCfg.setProperty("network.bootstrap.tracker", txtTracker.getText()); + } + + KeyPair netKey = CryptoUtils.createSignatureKeyPair(); + + netCfg.setPropertyBytes("network.publicKey", netKey.getPublic().getEncoded()); + netCfg.sign("network.signature", netKey.getPrivate()); + netCfg.setPropertyBytes("secret.network.privateKey", netKey.getPrivate().getEncoded()); + + AdvProperties accessCfg = MainControl.genereteAccess(netCfg, null); + mainControl.connectToNewNet(netCfg, accessCfg); + + setVisible(false); + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnCancel; + private javax.swing.JButton btnOK; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JTabbedPane jTabbedPane1; + private javax.swing.JTextField txtConnectTo; + private javax.swing.JTextField txtName; + private javax.swing.JTextField txtNetwork; + private javax.swing.JTextField txtSubnetMask; + private javax.swing.JTextField txtTracker; + // End of variables declaration//GEN-END:variables + +} diff --git a/src/org/p2pvpn/gui/OptionWindow.form b/src/org/p2pvpn/gui/OptionWindow.form new file mode 100644 index 0000000..bc95b07 --- /dev/null +++ b/src/org/p2pvpn/gui/OptionWindow.form @@ -0,0 +1,373 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/p2pvpn/gui/OptionWindow.java b/src/org/p2pvpn/gui/OptionWindow.java new file mode 100644 index 0000000..17fcce0 --- /dev/null +++ b/src/org/p2pvpn/gui/OptionWindow.java @@ -0,0 +1,419 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +// TODO option: use whatisymip + +package org.p2pvpn.gui; + +import java.net.URL; +import javax.swing.ImageIcon; +import org.p2pvpn.network.TCPConnection; + +/** + * This window is opened when the user wants to change the options. + * @author Wolfgang Ginolas + */ +public class OptionWindow extends javax.swing.JDialog { + + private boolean ok = false; + + /** Creates new form OptionWindow + * @param parent the parent window + */ + public OptionWindow(java.awt.Frame parent) { + super(parent, true); + setLocationByPlatform(true); + initComponents(); + try { + URL url = InfoWindow.class.getClassLoader().getResource("resources/images/options.png"); + setIconImage(new ImageIcon(url).getImage()); + } catch(Throwable e) {} + addWindowListener(new java.awt.event.WindowAdapter() { + public void windowClosing(java.awt.event.WindowEvent e) { + ok = false; + setVisible(false); + } + }); + + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jTabbedPane1 = new javax.swing.JTabbedPane(); + jPanel1 = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + txtName = new javax.swing.JTextField(); + jLabel2 = new javax.swing.JLabel(); + spnPort = new javax.swing.JSpinner(); + jLabel4 = new javax.swing.JLabel(); + spnSendLimit = new javax.swing.JSpinner(); + jLabel5 = new javax.swing.JLabel(); + jLabel6 = new javax.swing.JLabel(); + spnRecLimit = new javax.swing.JSpinner(); + jLabel7 = new javax.swing.JLabel(); + jPanel4 = new javax.swing.JPanel(); + chkPopupChat = new javax.swing.JCheckBox(); + jPanel2 = new javax.swing.JPanel(); + jLabel3 = new javax.swing.JLabel(); + txtIP = new javax.swing.JTextField(); + jPanel3 = new javax.swing.JPanel(); + jLabel8 = new javax.swing.JLabel(); + spnBufferSize = new javax.swing.JSpinner(); + jLabel9 = new javax.swing.JLabel(); + chkTCPFlush = new javax.swing.JCheckBox(); + btnReset = new javax.swing.JButton(); + btnCancel = new javax.swing.JButton(); + btnOK = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle("Options"); + + jLabel1.setText("Your Name"); + + jLabel2.setText("Listen on Port"); + + spnPort.setModel(new javax.swing.SpinnerNumberModel(56483, 0, 65525, 1)); + + jLabel4.setText("Max Upload"); + + spnSendLimit.setModel(new javax.swing.SpinnerNumberModel(Double.valueOf(0.0d), Double.valueOf(0.0d), null, Double.valueOf(10.0d))); + spnSendLimit.setToolTipText("0 = no limit"); + + jLabel5.setText("Max Download"); + jLabel5.setEnabled(false); + + jLabel6.setText("kb/s"); + + spnRecLimit.setModel(new javax.swing.SpinnerNumberModel(Double.valueOf(0.0d), Double.valueOf(0.0d), null, Double.valueOf(10.0d))); + spnRecLimit.setToolTipText("not implemented"); + spnRecLimit.setEnabled(false); + + jLabel7.setText("kb/s"); + jLabel7.setEnabled(false); + + org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jLabel2) + .add(jLabel1) + .add(jLabel4) + .add(jLabel5)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .add(spnRecLimit, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel7)) + .add(txtName, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE) + .add(spnPort, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel1Layout.createSequentialGroup() + .add(spnSendLimit, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 113, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel6))) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel1) + .add(txtName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel2) + .add(spnPort, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel4) + .add(spnSendLimit, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(spnRecLimit, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(jLabel5))) + .add(jPanel1Layout.createSequentialGroup() + .add(jLabel6) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(jLabel7))) + .addContainerGap(34, Short.MAX_VALUE)) + ); + + jTabbedPane1.addTab("Global", jPanel1); + + chkPopupChat.setText("Popup chat on incoming message"); + + org.jdesktop.layout.GroupLayout jPanel4Layout = new org.jdesktop.layout.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .add(chkPopupChat) + .addContainerGap(37, Short.MAX_VALUE)) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .add(chkPopupChat) + .addContainerGap(126, Short.MAX_VALUE)) + ); + + jTabbedPane1.addTab("UI", jPanel4); + + jLabel3.setText("VPN IP"); + + org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .add(jLabel3) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(txtIP, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 194, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel3) + .add(txtIP, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(124, Short.MAX_VALUE)) + ); + + jTabbedPane1.addTab("Network", jPanel2); + + jLabel8.setText("Send buffer size"); + + spnBufferSize.setModel(new javax.swing.SpinnerNumberModel(10, 1, 500, 1)); + + jLabel9.setText("packets"); + + chkTCPFlush.setText("Flush after each packet"); + chkTCPFlush.setEnabled(false); + + btnReset.setText("Rest to Defaults"); + btnReset.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnResetActionPerformed(evt); + } + }); + + org.jdesktop.layout.GroupLayout jPanel3Layout = new org.jdesktop.layout.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel3Layout.createSequentialGroup() + .add(jLabel8) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(spnBufferSize, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 81, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel9)) + .add(chkTCPFlush) + .add(btnReset)) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(jLabel8) + .add(spnBufferSize, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(jLabel9)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(chkTCPFlush) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnReset) + .addContainerGap(64, Short.MAX_VALUE)) + ); + + jTabbedPane1.addTab("Advanced", jPanel3); + + btnCancel.setText("Cancel"); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); + + btnOK.setText("OK"); + btnOK.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOKActionPerformed(evt); + } + }); + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .addContainerGap(174, Short.MAX_VALUE) + .add(btnOK) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnCancel) + .addContainerGap()) + .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 270, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 188, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(btnCancel) + .add(btnOK)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + +private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed + ok = true; + setVisible(false); +}//GEN-LAST:event_btnOKActionPerformed + +private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed + ok = false; + setVisible(false); +}//GEN-LAST:event_btnCancelActionPerformed + +private void btnResetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnResetActionPerformed + spnBufferSize.getModel().setValue(TCPConnection.DEFAULT_MAX_QUEUE); + chkTCPFlush.setSelected(TCPConnection.DEFAULT_TCP_FLUSH); +}//GEN-LAST:event_btnResetActionPerformed + + public void setNodeName(String name) { + txtName.setText(name); + } + + public String getNodeName() { + return txtName.getText(); + } + + public void setPort(int port) { + spnPort.getModel().setValue(port); + } + + public int getPort() { + return (Integer)spnPort.getModel().getValue(); + } + + public void setIP(String ip) { + txtIP.setText(ip); + } + + public String getIP() { + return txtIP.getText(); + } + + public boolean isOk() { + return ok; + } + + public void setSendLimit(double sendLimit) { + spnSendLimit.getModel().setValue(sendLimit/1024); + } + + public void setRecLimit(double recLimit) { + spnRecLimit.getModel().setValue(recLimit/1024); + } + + public double getSendLimit() { + return 1024*(Double)spnSendLimit.getModel().getValue(); + } + + public double getRecLimit() { + return 1024*(Double)spnRecLimit.getModel().getValue(); + } + + public int getSendBufferSize() { + return (Integer)spnBufferSize.getModel().getValue(); + } + + public void setSendBufferSize(int s) { + spnBufferSize.getModel().setValue(s); + } + + public boolean isTCPFlush() { + return chkTCPFlush.isSelected(); + } + + public void setTCPFlush(boolean f) { + chkTCPFlush.setSelected(f); + } + + public boolean isPopupChat() { + return chkPopupChat.isSelected(); + } + + public void setPopupChat(boolean p) { + chkPopupChat.setSelected(p); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnCancel; + private javax.swing.JButton btnOK; + private javax.swing.JButton btnReset; + private javax.swing.JCheckBox chkPopupChat; + private javax.swing.JCheckBox chkTCPFlush; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; + private javax.swing.JLabel jLabel6; + private javax.swing.JLabel jLabel7; + private javax.swing.JLabel jLabel8; + private javax.swing.JLabel jLabel9; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JTabbedPane jTabbedPane1; + private javax.swing.JSpinner spnBufferSize; + private javax.swing.JSpinner spnPort; + private javax.swing.JSpinner spnRecLimit; + private javax.swing.JSpinner spnSendLimit; + private javax.swing.JTextField txtIP; + private javax.swing.JTextField txtName; + // End of variables declaration//GEN-END:variables + +} diff --git a/src/org/p2pvpn/gui/PeerGraph.java b/src/org/p2pvpn/gui/PeerGraph.java new file mode 100644 index 0000000..196a5d3 --- /dev/null +++ b/src/org/p2pvpn/gui/PeerGraph.java @@ -0,0 +1,120 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + + +package org.p2pvpn.gui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.util.StringTokenizer; +import javax.swing.JComponent; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.PeerID; +import org.p2pvpn.network.Router; +import org.p2pvpn.network.RoutungTableListener; + +/** + * This Component shows a simple peer graph which is used in the info window + * @author Wolfgang Ginolas + */ +public class PeerGraph extends JComponent implements RoutungTableListener { + private static final int BORDER = 50; + private static final int NODE_SIZE = 20; + + private ConnectionManager connectionManager; + private Router router; + + public PeerGraph() { + super(); + setConnectionManager(null); + } + + public void setConnectionManager(ConnectionManager cm) { + connectionManager = cm; + if (connectionManager==null) { + router = null; + } else { + router = connectionManager.getRouter(); + router.addTableListener(this); + } + } + + public void tableChanged(Router router) { + repaint(); + } + + @Override + public void paint(Graphics g) { + if (router==null) return; + Graphics2D g2 = (Graphics2D)g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + FontMetrics fm = g.getFontMetrics(); + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + int size = Math.min(getWidth(), getHeight()) / 2 - BORDER; + + PeerID[] peers = router.getPeers(); + int[] px = new int[peers.length]; + int[] py = new int[peers.length]; + + for(int i=0; i. +*/ + +package org.p2pvpn.gui; + +import java.awt.Component; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.Transferable; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import org.p2pvpn.network.PeerID; + + +/** + * This Renderer renders the items in the peer list used in the MainWindow. + * @author Wolfgang Ginoas + */ +public class PeerListCellRenderer extends JLabel implements ListCellRenderer, ClipboardOwner { + + private static Icon directIcon = null; + private static Icon indirectIcon = null; + + private String ip; + + static { + try { + directIcon = new ImageIcon( + InfoWindow.class.getClassLoader().getResource("resources/images/direct.png")); + indirectIcon = new ImageIcon( + InfoWindow.class.getClassLoader().getResource("resources/images/indirect.png")); + } catch (NullPointerException e) { + } + } + + MainControl mainControl; + + public PeerListCellRenderer() { + super(); + mainControl = null; + } + + public void setMainControl(MainControl mainControl) { + this.mainControl = mainControl; + } + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + boolean direct = true; + String text = ""; + String toolTip = ""; + ip=null; + + if (mainControl!=null) { + PeerID peer = (PeerID)value; + + if (mainControl.getConnectionManager()!=null) { + direct = mainControl.getConnectionManager().getRouter().isConnectedTo(peer); + } + text = ""+mainControl.nameForPeer(peer); + toolTip = mainControl.descriptionForPeer(peer); + ip = mainControl.getConnectionManager().getRouter().getPeerInfo(peer, "vpn.ip"); + if (ip!=null) + text += " (" + ip + ")"; + } + + setText(text); + setIcon(direct ? directIcon : indirectIcon); + setToolTipText(toolTip); + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + setEnabled(list.isEnabled()); + setFont(list.getFont()); + setOpaque(true); + + /* Does not work this way + if (ip!=null) { // TODO repair + JPopupMenu menu = new JPopupMenu(); + JMenuItem mitem = new JMenuItem("Copy IP address"); + mitem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); + c.setContents(new StringSelection(ip), PeerListCellRenderer.this); + } + }); + menu.add(mitem); + setComponentPopupMenu(menu); + } + */ + + return this; + } + + public void lostOwnership(Clipboard clipboard, Transferable contents) { + } +} diff --git a/src/org/p2pvpn/gui/PeerListModel.java b/src/org/p2pvpn/gui/PeerListModel.java new file mode 100644 index 0000000..7217a35 --- /dev/null +++ b/src/org/p2pvpn/gui/PeerListModel.java @@ -0,0 +1,95 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.util.Vector; +import javax.swing.ListModel; +import javax.swing.SwingUtilities; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.PeerID; +import org.p2pvpn.network.Router; +import org.p2pvpn.network.RoutungTableListener; + +/** + * The Model for the peer list used in the MainWindow. + * @author Wolfgang Ginolas + */ +public class PeerListModel implements RoutungTableListener, ListModel { + + ConnectionManager connectionManager; + Vector listeners; + Vector list; + + public PeerListModel() { + connectionManager = null; + listeners = new Vector(); + list = new Vector(); + } + + public void tableChanged(Router router) { + PeerID[] peers = router.getPeers(); + list = new Vector(); + + for (PeerID peer : peers) { + if (!connectionManager.getLocalAddr().equals(peer)) { + list.add(peer); + } + } + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + notifyListeners(); + } + }); + } + + public void notifyListeners() { + for (ListDataListener l : listeners) { + l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, list.size())); + } + } + + public void setConnectionManager(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + if (connectionManager!=null) { + connectionManager.getRouter().addTableListener(this); + tableChanged(connectionManager.getRouter()); + } + } + + public int getSize() { + return list.size(); + } + + public Object getElementAt(int index) { + return list.get(index); + } + + public void addListDataListener(ListDataListener l) { + listeners.add(l); + } + + public void removeListDataListener(ListDataListener l) { + listeners.remove(l); + } + +} diff --git a/src/org/p2pvpn/gui/PeerTableModel.java b/src/org/p2pvpn/gui/PeerTableModel.java new file mode 100644 index 0000000..8ebc341 --- /dev/null +++ b/src/org/p2pvpn/gui/PeerTableModel.java @@ -0,0 +1,179 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.gui; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import javax.swing.SwingUtilities; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; +import org.p2pvpn.network.ConnectionManager; +import org.p2pvpn.network.P2PConnection; +import org.p2pvpn.network.PeerID; +import org.p2pvpn.network.Router; +import org.p2pvpn.network.RoutungTableListener; + +/** + * The Model for the peer table used in the info window. + * @author Wolfgang Ginolas + */ +public class PeerTableModel implements RoutungTableListener, TableModel { + + private static final NumberFormat BW_FORMAT = new DecimalFormat("0.0"); + private static final long UPDATE_MS = 500; + + /* + * Table Columns: Name, Id, Direct, IP, MAC, In, Out, ping + */ + + private ConnectionManager connectionManager; + private Router router; + private Vector listeners; + private PeerID[] table; + + public PeerTableModel(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + this.router = connectionManager.getRouter(); + router.addTableListener(this); + listeners = new Vector(); + table = router.getPeers(); + scheduleTableChanged(); + } + + public PeerID getPeerID(int row) { + return table[row]; + } + + @Override + public void tableChanged(Router router) { + table = router.getPeers(); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + notifyListeners(); + } + }); + } + + public void scheduleTableChanged() { + tableChanged(router); + connectionManager.getScheduledExecutor().schedule(new Runnable() { + public void run() { + scheduleTableChanged(); + } + }, UPDATE_MS, TimeUnit.MILLISECONDS); + } + + private void notifyListeners() { + for(TableModelListener l : listeners) { + l.tableChanged(new TableModelEvent(this)); + } + } + + @Override + public void addTableModelListener(TableModelListener l) { + listeners.add(l); + } + + @Override + public Class getColumnClass(int c) { + switch (c) { + case 0: return String.class; + case 1: return String.class; + case 2: return String.class; + case 3: return String.class; + case 4: return String.class; + case 5: return String.class; + case 6: return String.class; + case 7: return String.class; + default: return null; + } + } + + @Override + public int getColumnCount() { + return 8; + } + + @Override + public String getColumnName(int c) { + switch (c) { + case 0: return "Name"; + case 1: return "ID"; + case 2: return "Connection"; + case 3: return "IP"; + case 4: return "MAC"; + case 5: return "In (kb/s)"; + case 6: return "Out (kb/s)"; + case 7: return "Ping (ms)"; + default: return null; + } + } + + @Override + public int getRowCount() { + return table.length; + } + + @Override + public Object getValueAt(int r, int c) { + P2PConnection conn = router.getConnection(table[r]); + switch (c) { + case 0: return router.getPeerInfo(table[r], "name"); + case 1: return table[r].toString(); + case 2: + if (table[r].equals(connectionManager.getLocalAddr())) return "it's me"; + if (router.isConnectedTo(table[r])) return "direct"; + return "indirect"; + case 3: return router.getPeerInfo(table[r], "vpn.ip"); + case 4: return router.getPeerInfo(table[r], "vpn.mac"); + case 5: + case 6: + if (conn==null) return ""; + double bw; + if (c==5) { + bw = conn.getConnection().getBwIn().getBandwidth() / 1024; + } else { + bw = conn.getConnection().getBwOut().getBandwidth() / 1024; + } + return BW_FORMAT.format(bw); + case 7: + if (conn==null) return "-"; + return ""+(int)conn.getPingTime().getAverage(); + default: return null; + } + } + + @Override + public boolean isCellEditable(int r, int c) { + return false; + } + + @Override + public void removeTableModelListener(TableModelListener l) { + listeners.remove(l); + } + + @Override + public void setValueAt(Object o, int r, int c) { + } +} diff --git a/src/org/p2pvpn/network/ConnectionManager.java b/src/org/p2pvpn/network/ConnectionManager.java new file mode 100644 index 0000000..7f69953 --- /dev/null +++ b/src/org/p2pvpn/network/ConnectionManager.java @@ -0,0 +1,363 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; +import org.p2pvpn.network.bittorrent.BitTorrentTracker; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.net.URL; +import java.net.UnknownHostException; +import java.security.MessageDigest; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.p2pvpn.network.bandwidth.TokenBucket; +import org.p2pvpn.tools.AdvProperties; +import org.p2pvpn.tools.CryptoUtils; +import org.p2pvpn.tools.SocketAddrStr; + +/** + * The ConnectionManager is the central point of the P2PVPN network. It + * coordinates the different layers of the network. + * @author Wolfgang Ginolas + */ +public class ConnectionManager implements Runnable { + final static private String WHATISMYIP_URL = "http://whatismyip.com/automation/n09230945.asp"; + final static private long WHATISMYIP_REFRESH_S = 10*60; + + final static private double SEND_BUCKET_SIZE = 10 * 1024; + + private ServerSocket server; // the ServerSocked to accept connections + private int serverPort; // the local port + private PeerID localAddr; // the local PeerID + private ScheduledExecutorService scheduledExecutor; // a scheduled exicutor used for various tasks + private Router router; // the Router + private Connector connector; // the Connector + private UPnPPortForward uPnPPortForward; // currently not used + private BitTorrentTracker bitTorrentTracker; // the BitTorrentTracker + + private String whatIsMyIP; // the local IP returned by whatismyip.com + + private AdvProperties accessCfg; // the access invitation + private byte[] networkKey; // network key used for encryption + + private TokenBucket sendLimit, recLimit; // maximum bandwidth + private Pinger pinger; // the Pinger + + private int sendBufferSize; // the send buffer size + private boolean tcpFlush; // flush after each packet send? + + /** + * Create a new ConnectionManager + * @param accessCfg the access invitation + * @param serverPort the local server port + */ + public ConnectionManager(AdvProperties accessCfg, int serverPort) { + sendBufferSize = TCPConnection.DEFAULT_MAX_QUEUE; + tcpFlush = TCPConnection.DEFAULT_TCP_FLUSH; + this.serverPort = serverPort; + this.accessCfg = accessCfg; + scheduledExecutor = Executors.newScheduledThreadPool(10); + localAddr = new PeerID(accessCfg.getPropertyBytes("access.publicKey", null), true); + router = new Router(this); + connector = new Connector(this); + bitTorrentTracker = null; + //uPnPPortForward = new UPnPPortForward(this); + whatIsMyIP = null; + + sendLimit = new TokenBucket(0, SEND_BUCKET_SIZE); + recLimit = new TokenBucket(0, SEND_BUCKET_SIZE); + pinger = new Pinger(this); + + calcNetworkKey(); + + (new Thread(this, "ConnectionManager")).start(); + + scheduledExecutor.schedule(new Runnable() { + public void run() {checkWhatIsMyIP();} + }, 1, TimeUnit.SECONDS); + } + + /** + * Calculate the network key used for encryption + */ + private void calcNetworkKey() { + // byte[] b = accessCfg.getPropertyBytes("network.publicKey", null); + byte[] b = accessCfg.getPropertyBytes("network.signature", null); + MessageDigest md = CryptoUtils.getMessageDigest(); + md.update("secretKey".getBytes()); // make sure the key differs from + // other hashes created from the publicKey + networkKey = md.digest(b); + } + + /** + * Find out the IPs of the local network adapters. + */ + public void updateLocalIPs() { + String ipList=""; + String ipv6List=""; + try { + Enumeration is = NetworkInterface.getNetworkInterfaces(); + while (is.hasMoreElements()) { + NetworkInterface i = is.nextElement(); + + if (!i.getName().toLowerCase().startsWith("tap") && + !i.getDisplayName().toLowerCase().startsWith("tap") && + !i.getName().equals("lo")) { + + System.out.println("if: '"+i.getName()+"', '"+i.getDisplayName()+"'"); + Enumeration as = i.getInetAddresses(); + while (as.hasMoreElements()) { + InetAddress a = as.nextElement(); + if (a instanceof Inet4Address) { + String s = a.getHostAddress(); + //if (!s.startsWith("127") && !s.equals(router.getPeerInfo(localAddr, "vpn.ip"))) { + ipList = ipList + " " + s; + //} + } + if (a instanceof Inet6Address) { + String s = a.getHostAddress(); + ipv6List = ipv6List + " " + s; + } + } + } + } + } catch (SocketException ex) { + Logger.getLogger("").log(Level.WARNING, "", ex); + } + if (whatIsMyIP!=null) ipList = ipList + " " + whatIsMyIP; + router.setLocalPeerInfo("local.port", ""+serverPort); + router.setLocalPeerInfo("local.ips", ipList.substring(1)); + router.setLocalPeerInfo("local.ip6s", ipv6List.substring(1)); + } + + /** + * Periodically check the local IPs. + */ + private void checkWhatIsMyIP() { + try { + BufferedReader in = new BufferedReader(new InputStreamReader( + new URL(WHATISMYIP_URL).openConnection().getInputStream())); + InetAddress a = InetAddress.getByName(in.readLine()); + if (a instanceof Inet4Address) whatIsMyIP = a.getHostAddress(); + } catch (Exception ex) { + Logger.getLogger("").log(Level.WARNING, "can not determine external address", ex); + } + updateLocalIPs(); + scheduledExecutor.schedule(new Runnable() { + public void run() {checkWhatIsMyIP();} + }, WHATISMYIP_REFRESH_S, TimeUnit.SECONDS); + } + + public PeerID getLocalAddr() { + return localAddr; + } + + public AdvProperties getAccessCfg() { + return accessCfg; + } + + public ScheduledExecutorService getScheduledExecutor() { + return scheduledExecutor; + } + + /** + * Called, when a TCPConnection is established. + * @param connection the connection + */ + public void newConnection(TCPConnection connection) { + //Logger.getLogger("").log(Level.INFO, "new connection from/to: "+connection); + new P2PConnection(this, connection); + } + + /** + * Called, when a new P2PConnectrion is established. + * @param p2pConnection + */ + public void newP2PConnection(P2PConnection p2pConnection) { + //Logger.getLogger("").log(Level.INFO, "new P2P connection from/to: "+p2pConnection.getRemoteAddr() + // +" ("+p2pConnection.getConnection()+")"); + router.newP2PConnection(p2pConnection); + } + + /** + * A thread to accept connections from other peers. + */ + @Override + public void run() { + try { + server = new ServerSocket(serverPort); + serverPort = server.getLocalPort(); + Logger.getLogger("").log(Level.INFO, "listening on port "+server.getLocalPort()); + + while (true) { + Socket s = server.accept(); + new TCPConnection(this, s, networkKey); + } + } + catch (Exception e) { + Logger.getLogger("").log(Level.SEVERE, "Not listening on "+server.getLocalPort()+" anymore", e); + } + } + + /** + * Add the IPs stored in the access invitation to the known hosts list. + * @param accessCfg the access invitation + */ + public void addIPs(AdvProperties accessCfg) { + connector.addIPs(accessCfg); + String tracker = accessCfg.getProperty("network.bootstrap.tracker"); + if (tracker!=null) bitTorrentTracker = new BitTorrentTracker(this, tracker); + } + + /** + * Try to connect to the given host. + * @param host the host + * @param port the port + */ + public void connectTo(String host, int port) { + try { + connectTo(InetAddress.getByName(host), port); + } catch (UnknownHostException ex) { + Logger.getLogger("").log(Level.WARNING, "", ex); + } + } + + /** + * Try to connect to the given host. + * @param host the host + * @param port the port + */ + public void connectTo(InetAddress host, int port) { + new ConnectTask(host, port); + } + + /** + * Try to connect to the given host. + * @param addr the host and port using the format "hist:port" + */ + public void connectTo(String addr) { + try { + InetSocketAddress a = SocketAddrStr.parseSocketAddr(addr); + connectTo(a.getAddress(), a.getPort()); + } catch (Exception e) { + Logger.getLogger("").log(Level.WARNING, "", e); + } + } + + /** + * Stop this network and close all connections + */ + public void close() { + try { + scheduledExecutor.shutdownNow(); + router.close(); + if (server!=null) server.close(); + //TODO close connections + } catch (IOException e) { + Logger.getLogger("").log(Level.WARNING, "", e); + } + } + + /** + * A Task which tries to connect another peer + */ + private class ConnectTask implements Runnable { + private InetAddress host; + private int port; + + /** + * Try to connect another peer. + * @param host the host + * @param port the port + */ + public ConnectTask(InetAddress host, int port) { + this.host = host; + this.port = port; + (new Thread(this, "ConnectTask")).start(); + } + + @Override + public void run() { + Socket s; + //connector.addIP(host, port, null, null, "connecting", false); + try { + s = new Socket(host, port); + new TCPConnection(ConnectionManager.this, s, networkKey); + //connector.addIP(host, port, null, null, "connected", false); + } catch (Throwable e) { + //Logger.getLogger("").log(Level.WARNING, host+" "+port); + //connector.addIP(host, port, null, null, e.getMessage(), false); + } + } + } + + public int getServerPort() { + return serverPort; + } + + public Router getRouter() { + return router; + } + + public Connector getConnector() { + return connector; + } + + public UPnPPortForward getUPnPPortForward() { + return uPnPPortForward; + } + + public TokenBucket getSendLimit() { + return sendLimit; + } + + public TokenBucket getRecLimit() { + return recLimit; + } + + public int getSendBufferSize() { + return sendBufferSize; + } + + public void setSendBufferSize(int sendBufferSize) { + this.sendBufferSize = sendBufferSize; + } + + public boolean isTCPFlush() { + return tcpFlush; + } + + public void setTCPFlush(boolean tcpFlush) { + this.tcpFlush = tcpFlush; + } +} diff --git a/src/org/p2pvpn/network/Connector.java b/src/org/p2pvpn/network/Connector.java new file mode 100644 index 0000000..cc04f4e --- /dev/null +++ b/src/org/p2pvpn/network/Connector.java @@ -0,0 +1,417 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.p2pvpn.tools.AdvProperties; +import org.p2pvpn.tools.SocketAddrStr; + +/** + * This class maintains a list of known hosts and tries to connect them + * periodically. + * @author Wolfgang Ginolas + */ +public class Connector { + + private final static long RETRY_S = 5*60; + private final static long REMOVE_MS = 60*60*1000; + + ConnectionManager connectionManager; + Map ips; + + Vector listeners; + + /** + * Create a new Connector + * @param connectionManager the ConnectionManager + */ + public Connector(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + listeners = new Vector(); + ips = new HashMap(); + } + + /** + * Add a ConnectorListener. + * @param l the listener + */ + public void addListener(ConnectorListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + /** + * Remove a Connector Listener + * @param l the listener + */ + public void removeListener(ConnectorListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + /** + * Notify all ConnectorListeners. + */ + private void notifyListeners() { + ConnectorListener[] ls; + synchronized (listeners) { + ls = listeners.toArray(new ConnectorListener[0]); + } + for(ConnectorListener l : ls) { + try { + l.ipListChanged(this); + } + catch (Throwable t) { + Logger.getLogger("").log(Level.WARNING, "", t); + } + } + } + + /** + * Return all known hosts. + * @return the hosts + */ + public Endpoint[] getIPs() { + synchronized (ips) { + return ips.keySet().toArray(new Endpoint[0]); + } + } + + /** + * Return information about the given IP. + * @param e the IP + * @return the information + */ + public EndpointInfo getIpInfo(Endpoint e) { + synchronized (ips) { + return ips.get(e); + } + } + + /** + * Add an IP to the known hosts. + * @param ip the IP + * @param port the port + * @param peerID the PeerID ot null when it's unknown + * @param source the source of this information + * @param status the last known status if this host + * @param keep kepp the ip in the list for ever? + */ + public void addIP(byte[] ip, int port, PeerID peerID, String source, String status, boolean keep) { + Endpoint endpoint = new Endpoint(ip, port); + EndpointInfo endpointInfo = new EndpointInfo(peerID, source, status, keep); + connectionManager.getScheduledExecutor().schedule( + new AddIPLater(endpoint, endpointInfo), 0, TimeUnit.SECONDS); + } + + /** + * Add an IP to the known hosts. + * @param ip the IP + * @param port the port + * @param peerID the PeerID ot null when it's unknown + * @param source the source of this information + * @param status the last known status if this host + * @param keep kepp the ip in the list for ever? + */ + public void addIP(String ip, int port, PeerID peerID, String source, String status, boolean keep) { + try { + addIP(InetAddress.getByName(ip).getAddress(), port, peerID, source, status, keep); + } catch (UnknownHostException ex) { + Logger.getLogger("").log(Level.WARNING, "unknown host "+ip, ex); + } + } + + /** + * Add an IP to the known hosts. + * @param ip the IP + * @param port the port + * @param peerID the PeerID ot null when it's unknown + * @param source the source of this information + * @param status the last known status if this host + * @param keep kepp the ip in the list for ever? + */ + public void addIP(InetAddress ip, int port, PeerID peerID, String source, String status, boolean keep) { + addIP(ip.getAddress(), port, peerID, source, status, keep); + } + + /** + * Add the IPs given in the access invitation. + * @param p the access invitation + */ + public void addIPs(AdvProperties p) { + int i=0; + + while(p.containsKey("network.bootstrap.connectTo."+i)) { + try { + InetSocketAddress a = SocketAddrStr.parseSocketAddr(p.getProperty("network.bootstrap.connectTo." + i)); + addIP(a.getAddress(), a.getPort(), null, "bootstrap", "", true); + } catch (Throwable t) { + Logger.getLogger("").log(Level.WARNING, "", t); + } + i++; + } + } + + /** + * Schedule a connection attempt. + * @param e the host to connect + * @param delay the delay + */ + private void scheduleConnect(Endpoint e, long delay) { + connectionManager.getScheduledExecutor().schedule(new ConnectRunnable(e), delay, TimeUnit.SECONDS); + } + + /** + * A Thread which adds an IP to the known host list. + */ + private class AddIPLater implements Runnable { + private Endpoint endpoint; + private EndpointInfo endpointInfo; + + /** + * Add the given IP later. + * @param endpoint the Host + * @param endpointInfo host information + */ + public AddIPLater(Endpoint endpoint, EndpointInfo endpointInfo) { + this.endpoint = endpoint; + this.endpointInfo = endpointInfo; + } + + /** + * Add the IP. + */ + public void run() { + boolean schedule = false; + synchronized (ips) { + if (!ips.containsKey(endpoint)) { + ips.put(endpoint, endpointInfo); + //try { + // System.out.println("add: " + endpoint.getInetAddress()); + //} catch (UnknownHostException ex) { + // Logger.getLogger(Connector.class.getName()).log(Level.SEVERE, null, ex); + //} + schedule = true; + } else { + ips.get(endpoint).update(endpointInfo.peerID, + endpointInfo.getSource(), endpointInfo.getStatus(), endpointInfo.isKeepForEver()); + } + } + if (schedule) scheduleConnect(endpoint, 1); + notifyListeners(); + } + } + + /** + * Try to connect to the given Host. + */ + private class ConnectRunnable implements Runnable { + Endpoint e; + + /** + * Try to connect to the given Host. + * @param e the host + */ + public ConnectRunnable(Endpoint e) { + this.e = e; + } + + /** + * Connect the host. + */ + public void run() { + try { + EndpointInfo info; + synchronized (ips) { + info = ips.get(e); + } + if (info == null) { + return; + } + + if (!connectionManager.getRouter().isConnectedTo(info.peerID)) { + try { + connectionManager.connectTo(e.getInetAddress(), e.getPort()); + } catch (UnknownHostException ex) { + } + } else { + info.update(); + } + //System.out.println("Check: "+e.getInetAddress()); + if (System.currentTimeMillis() - REMOVE_MS > info.timeAdded) { + synchronized (ips) { + ips.remove(e); + } + //System.out.println("removed"); + notifyListeners(); + } + } catch (Throwable t) { + } + scheduleConnect(e, RETRY_S); + } + + } + + /*** + * A Host (IP and port). + */ + public class Endpoint { + byte[] ip; + int port; + + /** + * Create a new Endpoint. + * @param ip the ip + * @param port the port + */ + public Endpoint(byte[] ip, int port) { + this.ip = ip; + this.port = port; + } + + public byte[] getIp() { + return ip; + } + + public InetAddress getInetAddress() throws UnknownHostException { + return InetAddress.getByAddress(ip); + } + + public int getPort() { + return port; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Endpoint other = (Endpoint) obj; + if (this.port != other.port) { + return false; + } + if (!Arrays.equals(ip, other.ip)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 59 * hash + (this.ip != null ? Arrays.hashCode(ip) : 0); + hash = 59 * hash + this.port; + return hash; + } + + @Override + public String toString() { + try { + return SocketAddrStr.socketAddrToStr(new InetSocketAddress(InetAddress.getByAddress(ip), port)); + } catch (UnknownHostException ex) { + return "unknown host"; + } + } + } + + /** + * Information about a host. + */ + public class EndpointInfo { + PeerID peerID; + long timeAdded; + String source; + String status; + boolean keepForEver; + + /** + * Create a new EndpointInfo. + * @param peerID the PeerID + * @param source the source of this host + * @param status the status of the host + * @param keepForEver keep this host for ever? + */ + EndpointInfo(PeerID peerID, String source, String status, boolean keepForEver) { + this.peerID = peerID; + this.source = source; + this.status = status; + this.keepForEver = keepForEver; + update(); + } + + EndpointInfo() { + this(null, null, "", false); + } + + void update() { + timeAdded = System.currentTimeMillis(); + } + + /** + * Update the hist info + * @param peerID the PeerID + * @param source the source of this host + * @param status the status of the host + * @param keepForEver keep this host for ever? + */ + void update(PeerID peerID, String source, String status, boolean keepForEver) { + if (peerID!=null) this.peerID = peerID; + if (source!=null) this.source = source; + if (status!=null) this.status = status; + if (keepForEver) this.keepForEver = true; + timeAdded = System.currentTimeMillis(); + } + + public boolean isKeepForEver() { + return keepForEver; + } + + public String getSource() { + return source; + } + + public String getStatus() { + return status; + } + + public PeerID getPeerID() { + return peerID; + } + + public long getTimeAdded() { + return timeAdded; + } + } +} diff --git a/src/org/p2pvpn/network/ConnectorListener.java b/src/org/p2pvpn/network/ConnectorListener.java new file mode 100644 index 0000000..070a0a3 --- /dev/null +++ b/src/org/p2pvpn/network/ConnectorListener.java @@ -0,0 +1,32 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; + +/** + * A listene which is notified, when the list of known IPs changes. + * @author wolfgang + */ +public interface ConnectorListener { + /** + * The list of known IPs changed. + * @param c the Connector + */ + public void ipListChanged(Connector c); +} diff --git a/src/org/p2pvpn/network/InternalPacketListener.java b/src/org/p2pvpn/network/InternalPacketListener.java new file mode 100644 index 0000000..2dd5cc2 --- /dev/null +++ b/src/org/p2pvpn/network/InternalPacketListener.java @@ -0,0 +1,34 @@ +/* + Copyright 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; + +/** + * A listener which can receive internal packages. + * @author wolfgang + */ +public interface InternalPacketListener { + /** + * Called when an internal packet for this listener arrived. + * @param router the Router + * @param internalPort the internal port + * @param data the data + */ + public void receiveInternalPacket(Router router, byte internalPort, byte[] data); +} diff --git a/src/org/p2pvpn/network/MacAddress.java b/src/org/p2pvpn/network/MacAddress.java new file mode 100644 index 0000000..d966c5e --- /dev/null +++ b/src/org/p2pvpn/network/MacAddress.java @@ -0,0 +1,150 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; + +import java.util.StringTokenizer; + +/** + * This class represents an Mac-Address. + * @author wolfgang + */ +public class MacAddress { + private long address; + + /** + * Create a new MacAddress using 6 bytes in the array starting at the + * given offset + * @param address the byte array + * @param off the offset + */ + public MacAddress(byte[] address, int off) { + setAddress(address, off); + } + + /** + * Create a new MacAddress + * @param address the address (6 bytes) + */ + public MacAddress(byte[] address) { + setAddress(address); + } + + /** + * Create a new MacAddress + * @param s the address using the format "xx:xx:xx:xx:xx:xx" + */ + public MacAddress(String s) { + byte[] addr = new byte[6]; + StringTokenizer st = new StringTokenizer(s, ":"); + int i; + + i=0; + while(i<6 && st.hasMoreTokens()) { + addr[i] = (byte)Integer.parseInt(st.nextToken(), 16); + i++; + } + + setAddress(addr); + } + + /** + * Set the address. + * @param address the byte array + * @param off the offset + */ + public void setAddress(byte[] address, int off) { + assert address.length>=off+6; + + this.address = 0; + for(int i=0; i<6; i++) { + this.address <<= 8; + this.address += ((int)address[i+off]) & 0xFF; + } + } + + /** + * Set the address. + * @param address the address + */ + public void setAddress(byte[] address) { + setAddress(address, 0); + } + + /** + * Return the address as byte array + * @return the address + */ + public byte[] getAddress() { + byte[] result = new byte[6]; + + long a = address; + + for(int i=5; i>=0; i--) { + result[i] = (byte)(a & 0xFF); + a >>= 8; + } + return result; + } + + /** + * Is this mac address an broadcast address? + * @return is this mac address an broadcast address? + */ + public boolean isBroadcast() { + return 0 != (address & 0x010000000000l); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (address ^ (address >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MacAddress other = (MacAddress) obj; + if (address != other.address) + return false; + return true; + } + + public String toString() { + byte[] a = getAddress(); + StringBuffer result = new StringBuffer(""); + + for(int i=0; i<6; i++) { + if (i!=0) result.append(':'); + int b = ((int)a[i]) & 0xFF; + if (b < 0x10) result.append('0'); + result.append(Integer.toString(b, 16)); + } + + return result.toString(); + } + +} diff --git a/src/org/p2pvpn/network/P2PConnection.java b/src/org/p2pvpn/network/P2PConnection.java new file mode 100644 index 0000000..5212e73 --- /dev/null +++ b/src/org/p2pvpn/network/P2PConnection.java @@ -0,0 +1,221 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.crypto.Cipher; +import org.p2pvpn.network.bandwidth.SlidingAverage; +import org.p2pvpn.tools.AdvProperties; +import org.p2pvpn.tools.CryptoUtils; + +/** + * The autorisation layer of the network. If checks if a remote peer is allowed + * to be part of this network. + * @author Wolfgang Ginolas + */ +public class P2PConnection { + + private static final int PING_BUCKET_LEN = 10; + + private enum P2PConnState {WAIT_FOR_ACCESS, + WAIT_FOR_KEY, CONNECTED}; + + private P2PConnState state; // the current state + + private byte[] myKeyPart; // my key part + + private ConnectionManager connectionManager; // the ConnectionManager + private TCPConnection connection; // the underlying TCPConnection + private ScheduledFuture schedTimeout; // used for a connect timeout + private PeerID remoteAddr; // the remote PeerID + private AdvProperties remoteAccess; // the remote access invitation + private long remoteExpiryDate; // the remote date of expiry + private Router router; // the router + + private SlidingAverage pingTime; // the latency for this connection + + + /** + * Create a new P2PConnetion + * @param connectionManager the ConnectionManager + * @param connection the TCPConnection + */ + public P2PConnection(ConnectionManager connectionManager, + TCPConnection connection) { + + pingTime = new SlidingAverage(PING_BUCKET_LEN, 0); + this.connectionManager = connectionManager; + this.connection = connection; + + remoteAddr = null; + + connection.setListener(this); + + AdvProperties access = connectionManager.getAccessCfg().filter("access", false); + connection.send(access.asBytes(), true); + state = P2PConnState.WAIT_FOR_ACCESS; + + schedTimeout = + connectionManager.getScheduledExecutor().schedule(new Runnable() { + public void run() { + timeout(); + } + }, 30, TimeUnit.SECONDS); + } + + public TCPConnection getConnection() { + return connection; + } + + public PeerID getRemoteAddr() { + return remoteAddr; + } + + /** + * Called when the connection timed out. + */ + private void timeout() { + if (state!=P2PConnState.CONNECTED) { + Logger.getLogger("").log(Level.INFO, "Timeout in handshake with "+connection.toString()+ + " in state: "+state); + connection.close(); + } + } + + /** + * Called, when the connection closed. + */ + public void connectionClosed() { + Logger.getLogger("").log(Level.INFO, "P2P connection to "+connection+" lost"); + if (router!=null) router.connectionClosed(this); + } + + /** + * Called, when a packat arrived. + * @param packet the packet + */ + public void receive(byte[] packet) { + try { + switch (state) { + case WAIT_FOR_ACCESS: { + remoteAccess = new AdvProperties(packet); + remoteAddr = new PeerID(remoteAccess.getPropertyBytes("access.publicKey", null), true); + PublicKey netKey = CryptoUtils.decodeRSAPublicKey( + connectionManager.getAccessCfg().getPropertyBytes("network.publicKey", null)); + + // if (!remoteAccess.verify("access.signature", netKey)) { // check signature + // Logger.getLogger("").log(Level.WARNING, remoteAddr+" has no valid access!"); + // close(); + // break; + // } + + + try { + remoteExpiryDate = Long.parseLong(remoteAccess.getProperty("access.expiryDate")); + } catch (NumberFormatException numberFormatException) { + remoteExpiryDate = 0; + } + if (remoteInvitatonExpired()) { + Logger.getLogger("").log(Level.WARNING, remoteAddr+" has expired!"); + close(); + break; + } + + SecureRandom rnd = CryptoUtils.getSecureRandom(); + myKeyPart = new byte[CryptoUtils.getSymmetricKeyLength()]; + rnd.nextBytes(myKeyPart); + + PublicKey remoteKey = CryptoUtils.decodeRSAPublicKey( + remoteAccess.getPropertyBytes("access.publicKey", null)); + + Cipher c = CryptoUtils.getAsymmetricCipher(); + c.init(Cipher.ENCRYPT_MODE, remoteKey, rnd); + + connection.send(c.doFinal(myKeyPart), true); + + state = P2PConnState.WAIT_FOR_KEY; + break; + } + case WAIT_FOR_KEY: { + PrivateKey myKey = CryptoUtils.decodeRSAPrivateKey( + connectionManager.getAccessCfg().getPropertyBytes("secret.access.privateKey", null)); + Cipher c = CryptoUtils.getAsymmetricCipher(); + c.init(Cipher.DECRYPT_MODE, myKey); + byte[] remoteKeyPart = c.doFinal(packet); + byte[] key = new byte[myKeyPart.length]; + + for(int i=0; i. +*/ + +package org.p2pvpn.network; +import java.io.Serializable; +import java.security.MessageDigest; +import java.util.Arrays; +import org.apache.commons.codec.binary.Base64; +import org.p2pvpn.tools.CryptoUtils; + +/** + * PeerID ist an unique ID for every peer. + * @author Wolfgang Ginolas + */ +public class PeerID implements Comparable, Serializable { + private static int idLen = CryptoUtils.getMessageDigest().getDigestLength(); + + private byte[] id; + + /** + * Create a new PeerID. + * @param b the ID + * @param hash use the hash of b as ID? + */ + public PeerID(byte[] b, boolean hash) { + if (hash) { + MessageDigest md = CryptoUtils.getMessageDigest(); + id = md.digest(b); + } else { + id = b; + } + } + + /** + * Create a new PeerID + * @param addrStr the ID as Base64 String. + */ + public PeerID(String addrStr) { + id = Base64.decodeBase64(addrStr.getBytes()); + } + + /** + * The length of PeerIDs. + * @return the length in bytes + */ + public static int getIdLen() { + return idLen; + } + + /** + * The ID as an byte array + * @return the bytes + */ + public byte[] getId() { + return id; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PeerID other = (PeerID) obj; + if (this.id != other.id && (this.id == null || !Arrays.equals(id, other.id))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Arrays.hashCode(id); + } + + public int compareTo(PeerID o) { + int d = id.length - o.id.length; + if (d!=0) return d; + for(int i=0; i. +*/ + +package org.p2pvpn.network; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +/** + * This class periodically sends ping packats to all naibour peers. + * @author Wolfgang Ginolas + */ +public class Pinger implements InternalPacketListener { + + private final static byte PING_REQUEST = 0; + private final static byte PING_REPLY = 1; + + private final static long MAX_PING_TIME_MS = 10 * 1000; + private final static long PING_INTERVALL_MS = 1 * 1000; + + private ConnectionManager connectionManager; // the ConnectionManager + private Router router; // the Router + private Random random; // used for random numbers + private Map pings; // the currently running pings + + /** + * Create a new Pinger. + * @param connectionManager the ConnectionManager + */ + public Pinger(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + router = connectionManager.getRouter(); + random = new Random(); + pings = new HashMap(); + + router.addInternalPacketListener(Router.INTERNAL_PORT_PING, this); + + schedulePing(); + } + + /** + * Send ping requests to all naibours. + */ + private void pingAll() { + P2PConnection[] cs = router.getConnections(); + for(P2PConnection c : cs) { + PeerID id = c.getRemoteAddr(); + String macStr = router.getPeerInfo(id, "vpn.mac"); + if (macStr!=null) { + MacAddress mac = new MacAddress(macStr); + sendPingRequest(mac); + } + } + + // remove old pings + long time = System.currentTimeMillis(); + synchronized (this) { + Iterator iter = pings.values().iterator(); + while(iter.hasNext()) { + PingInfo i = iter.next(); + if (time-i.getSendTime() > MAX_PING_TIME_MS) { + iter.remove(); + P2PConnection c = router.getP2PConnection(i.getMac()); + if (c!=null) c.getPingTime().putVaule(MAX_PING_TIME_MS); + } + } + } + schedulePing(); + } + + /** + * Schedule the nect ping request. + */ + private void schedulePing() { + connectionManager.getScheduledExecutor().schedule(new Runnable() { + public void run() { + pingAll(); + } + }, PING_INTERVALL_MS, TimeUnit.MILLISECONDS); + } + + /** + * Send a ping request. + * @param to the destination + */ + private void sendPingRequest(MacAddress to) { + byte[] packet = new byte[1 + 2 + 6]; + int id; + + synchronized (this) { + id = random.nextInt() & 0xFFFF; + pings.put(id, new PingInfo(to)); + } + + packet[0] = PING_REQUEST; + packet[1] = (byte)(id >> 8); + packet[2] = (byte)(id & 0xFF); + System.arraycopy(router.getMyMAC().getAddress(), 0, packet, 3, 6); + router.sendInternalPacket(to, Router.INTERNAL_PORT_PING, packet); + //System.out.println("ping request to "+to); + } + + /** + * Send a ping replay + * @param request the request packet + */ + private void sendPingReply(byte[] request) { + if (request.length==9) { + byte[] packet = new byte[1 + 2]; + byte[] mac = new byte[6]; + + packet[0] = PING_REPLY; + packet[1] = request[1]; // copy the Ping ID + packet[2] = request[2]; + + router.sendInternalPacket(new MacAddress(request, 3), Router.INTERNAL_PORT_PING, packet); + //System.out.println("ping reply to "+new MacAddress(request, 3)); + } + } + + /** + * Handle a recheives ping reply. + * @param packet the replay packet + */ + private void handlePingReply(byte[] packet) { + long time = System.currentTimeMillis(); + if (packet.length==3) { + int id = ((0xFF & packet[1]) << 8) + (0xFF & packet[2]); + + PingInfo info; + synchronized (this) { + info = pings.get(id); + pings.remove(id); + } + if (info!=null) { + P2PConnection c = router.getP2PConnection(info.getMac()); + //System.out.println("ping reply from "+info.getMac()); + if (c!=null) { + c.getPingTime().putVaule(time - info.getSendTime()); + } + } + } + } + + /** + * Calles when a ping request or reply arrived + * @param router the Router + * @param internalPort the internal port + * @param packet the packet + */ + public void receiveInternalPacket(Router router, byte internalPort, byte[] packet) { + if (internalPort != Router.INTERNAL_PORT_PING) return; + + switch (packet[0]) { + case PING_REQUEST: + sendPingReply(packet); + break; + + case PING_REPLY: + handlePingReply(packet); + break; + default: + } + } + + /** + * Information about a running ping. + */ + private class PingInfo { + private long sendTime; + private MacAddress mac; + + /** + * Create a new PingInfo. + * @param mac the destination + */ + public PingInfo(MacAddress mac) { + this.sendTime = System.currentTimeMillis(); + this.mac = mac; + } + + public MacAddress getMac() { + return mac; + } + + /** + * @return the time when the ping request was send + */ + public long getSendTime() { + return sendTime; + } + } + +} diff --git a/src/org/p2pvpn/network/Router.java b/src/org/p2pvpn/network/Router.java new file mode 100644 index 0000000..9ff464c --- /dev/null +++ b/src/org/p2pvpn/network/Router.java @@ -0,0 +1,754 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Random; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeMap; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.p2pvpn.tools.VersionizedMap; + +/** + * All packets are running throug the Router. Packages are received from the + * neighbour peers and the VPNConnecter and send to the neighbour peers or the + * VPNConnector accordting to the destination address. + * @author wolfgang + */ +public class Router implements RoutungTableListener { + private static final long SYNC_TIME = 5; // seconds + private static final long CONN_TIMEOUT_MS = 60 * 1000; + + private static final byte DATA_PACKET = 0; + private static final byte DATA_BROADCAST_PACKET = 1; + private static final byte ASK_DB = 2; + private static final byte SEND_DB = 3; + private static final byte INTERNAL_PACKET = 4; + + public static final byte INTERNAL_PORT_CHAT = -1; + public static final byte INTERNAL_PORT_PING = 1; + + private ConnectionManager connectionManager; // the ConnectioionManager + private VPNConnector vpnConnector; // the VpnConnector + + private Map connections; // all connections + private Map> peers; // all peers + private Map routeCache; // cached routes + + private MacAddress myMAC; // local mac address + private boolean gotMacFromTun; // was the mac address received from the und interface? + + private Vector tableListeners; // listeners of the peer list + + private Map internalListeners; // listeners for internal packets + + /** + * Create a new Router + * @param connectionManager the ConnectionManager + */ + public Router(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + tableListeners = new Vector(); + connections = new HashMap(); + routeCache = new HashMap(); + internalListeners = new HashMap(); + peers = new HashMap>(); + peers.put(connectionManager.getLocalAddr(), new VersionizedMap()); + setRandomMac(); + gotMacFromTun = false; + + connectionManager.getScheduledExecutor().schedule(new Runnable() { + public void run() { + syncDB(); + } + }, SYNC_TIME, TimeUnit.SECONDS); + } + + /** + * Add a listener for the peer list. + * @param l the listener + */ + public synchronized void addTableListener(RoutungTableListener l) { + tableListeners.add(l); + } + + /** + * Return all knpown peers. + * @return the peers + */ + public synchronized PeerID[] getPeers() { + return peers.keySet().toArray(new PeerID[0]); + } + + /** + * Return all known mac addresses. + * @param withLocalMac include the local mac address + * @return the addresses + */ + private synchronized Set getKnownMACs(boolean withLocalMac) { + Set result = new HashSet(); + for(Map.Entry> e : peers.entrySet()) { + if (withLocalMac || !e.getKey().equals(connectionManager.getLocalAddr())) { + String mac = e.getValue().get("vpn.mac"); + if (mac!=null) { + result.add(new MacAddress(mac)); + } + } + } + return result; + } + + /** + * Return the ID of the peer with the given mac address. + * @param mac the addrress + * @return the PeerID + */ + private PeerID findAddressForMac(MacAddress mac) { + String macStr = mac.toString(); + for(Map.Entry> e : peers.entrySet()) { + if (macStr.equals(e.getValue().get("vpn.mac"))) return e.getKey(); + } + return null; + } + + /** + * Calculate a route to another peer wothout caching. + * @param macDest the osther peer + * @return list of naighbours with the shortest connection to the destination + */ + private P2PConnection[] findRouteInt(MacAddress macDest) { + if (macDest.equals(myMAC)) return new P2PConnection[0]; + + // find Address + PeerID dest = findAddressForMac(macDest); + if (dest==null) return new P2PConnection[0]; + + Queue queue = new LinkedList(); + Map dist = new HashMap(); + queue.offer(dest); + dist.put(dest, 0); + + while (!queue.isEmpty() && !dist.containsKey(connectionManager.getLocalAddr())) { + PeerID a = queue.remove(); + int d = dist.get(a); + + String conn = getPeerInfo(a, "connectedTo"); + if (conn!=null) { + StringTokenizer st = new StringTokenizer(conn); + + while(st.hasMoreTokens()) { + PeerID next = new PeerID(st.nextToken()); + + if (!dist.containsKey(next)) { + dist.put(next, d+1); + queue.offer(next); + } + } + } + } + + Integer maxDist = dist.get(connectionManager.getLocalAddr()); + if (maxDist == null) return new P2PConnection[0]; + Collection result = new Vector(); + + synchronized (this) { + //System.out.println("Routing: dist to "+dest+" = "+maxDist); + for(PeerID a : connections.keySet()) { + Integer d = dist.get(a); + if (d!=null && d == maxDist - 1) { + //System.out.println(" next peer: "+a); + result.add(connections.get(a)); + } + } + } + return result.toArray(new P2PConnection[0]); + } + + /** + * Calculate a route to another peer with caching. + * @param macDest the osther peer + * @return list of naighbours with the shortest connection to the destination + */ + private P2PConnection[] findRoute(MacAddress macDest) { + P2PConnection[] result; + synchronized (this) { + result = routeCache.get(macDest); + } + + if (result==null) result = findRouteInt(macDest); + + synchronized (this) { + routeCache.put(macDest, result); + } + return result; + } + + /** + * Find a naigbour with the given mac address. + * @param mac the mac address + * @return the P2PCpnnection to the neighbour + */ + public P2PConnection getP2PConnection(MacAddress mac) { + P2PConnection[] cs = findRoute(mac); + for (P2PConnection c : cs) { + PeerID id = c.getRemoteAddr(); + String macStr = getPeerInfo(id, "vpn.mac"); + if (macStr!=null) { + MacAddress oMac = new MacAddress(macStr); + if (oMac.equals(mac)) return c; + } + } + return null; + } + + /** + * Find all peers that are reachable from the given peer. + * @param reachable the set of reachable peers + * @param a the peer + */ + private void _addReachablePeer(Set reachable, PeerID a) { + if (reachable.contains(a)) return; + + reachable.add(a); + VersionizedMap db = peers.get(a); + if (db!=null) { + String conn = db.get("connectedTo"); + if (conn!=null) { + StringTokenizer st = new StringTokenizer(conn); + + while(st.hasMoreTokens()) { + _addReachablePeer(reachable, new PeerID(st.nextToken())); + } + } + } + } + + /** + * Update the peer list after the network topology changed. + */ + private synchronized void updatePeers() { + Set reachable = new HashSet(); + + routeCache.clear(); + + _addReachablePeer(reachable, connectionManager.getLocalAddr()); + + Iterator as = peers.keySet().iterator(); + + while(as.hasNext()) { + PeerID a = as.next(); + if (!reachable.contains(a)) as.remove(); + } + + for(PeerID a : reachable) { + if (!peers.containsKey(a)) { + peers.put(a, new VersionizedMap()); + } + } + } + + /** + * Send the database of a peer. + * @param connection sent to this connection + * @param a the peer + */ + private void sendDBPacket(P2PConnection connection, PeerID a) { + try { + ByteArrayOutputStream outB = new ByteArrayOutputStream(); + outB.write(SEND_DB); + ObjectOutputStream outO = new ObjectOutputStream(outB); + outO.writeObject(a); + synchronized (this) { + outO.writeObject(peers.get(a)); + } + outO.flush(); + connection.send(outB.toByteArray(), true); + } catch (IOException ex) { + } + } + + /** + * Disconnect from neighbours which did not send a apcket for some time or + * the invitation expired. + */ + private void removeDeadPeers() { + P2PConnection[] cs = getConnections(); + long time = System.currentTimeMillis(); + + for(P2PConnection c : cs) { + if ((time - c.getConnection().getLastActive() > CONN_TIMEOUT_MS) + || c.remoteInvitatonExpired()) c.close(); + } + } + + /** + * Request the databases of all peers. + */ + private void syncDB() { + try { + Set peerSet; + + removeDeadPeers(); + P2PConnection[] cs = getConnections(); + + synchronized (this) { + peerSet = peers.keySet(); + } + + for (PeerID a : peerSet) { + P2PConnection c = null; + + if (!a.equals(connectionManager.getLocalAddr())) { + long version; + synchronized (this) { + if (connections.containsKey(a)) { + c = connections.get(a); + } else { + c = cs[(int) (Math.random() * cs.length)]; + } + version = peers.get(a).getVersion(); + } + + try { + ByteArrayOutputStream outB = new ByteArrayOutputStream(); + outB.write(ASK_DB); + ObjectOutputStream outO = new ObjectOutputStream(outB); + outO.writeObject(a); + outO.writeLong(version); + outO.flush(); + c.send(outB.toByteArray(), true); + } catch (IOException ex) { + } + } + } + } catch (Throwable e) { + } + + connectionManager.getScheduledExecutor().schedule(new Runnable() { + public void run() { + syncDB(); + } + }, SYNC_TIME, TimeUnit.SECONDS); + } + + /** + * Notify all listeners that the peer list changed. + * @param connectionsChanged did the list of neighbours change? + */ + private void notifyListeners(boolean connectionsChanged) { + + if (connectionsChanged) { + synchronized (this) { + StringBuffer cs = new StringBuffer(); + boolean first = true; + for(P2PConnection c : connections.values()) { + if (!first) cs.append(" "); + cs.append(c.getRemoteAddr()); + first = false; + } + peers.get(connectionManager.getLocalAddr()).put("connectedTo", cs.toString()); + } + } + + updatePeers(); + + RoutungTableListener[] ls; + synchronized (this) { + ls = tableListeners.toArray(new RoutungTableListener[0]); + } + + for(RoutungTableListener l : ls) { + l.tableChanged(this); + } + } + + /** + * Called when the database for a peer changed. Update the network topolpgy + * and the list of known IPs. + * @param a the peer + */ + private void dbChanged(PeerID a) { + notifyListeners(false); + + // check for local IPs + if (!a.equals(connectionManager.getLocalAddr())) { + String port; + String ips, ip6s; + synchronized (this) { + port = peers.get(a).get("local.port"); + ips = peers.get(a).get("local.ips"); + ip6s = peers.get(a).get("local.ip6s"); + } + if (port!=null && ips!=null) { + StringTokenizer st = new StringTokenizer(ips); + while (st.hasMoreTokens()) { + try { + connectionManager.getConnector().addIP(st.nextToken(), Integer.parseInt(port), + a, "peer exchange", "", false); + } catch (NumberFormatException numberFormatException) { + Logger.getLogger("").log(Level.WARNING, "", numberFormatException); + } + } + } + if (port!=null && ip6s!=null) { + StringTokenizer st = new StringTokenizer(ip6s); + while (st.hasMoreTokens()) { + try { + connectionManager.getConnector().addIP(st.nextToken(), Integer.parseInt(port), + a, "peer exchange", "", false); + } catch (NumberFormatException numberFormatException) { + Logger.getLogger("").log(Level.WARNING, "", numberFormatException); + } + } + } + } + } + + public synchronized String getPeerInfo(PeerID peer, String key) { + VersionizedMap db = peers.get(peer); + if (db==null) return null; + return db.get(key); + } + + public synchronized Map getPeerInfo(PeerID peer) { + VersionizedMap db = peers.get(peer); + if (db==null) return null; + return new TreeMap(db); + } + + public void setLocalPeerInfo(String key, String val) { + synchronized (this) { + peers.get(connectionManager.getLocalAddr()).put(key, val); + } + notifyListeners(false); + } + + public synchronized P2PConnection[] getConnections() { + return connections.values().toArray(new P2PConnection[0]); + } + + public synchronized P2PConnection getConnection(PeerID id) { + return connections.get(id); + } + + public synchronized boolean isConnectedTo(PeerID id) { + if (id==null) return false; + return connections.containsKey(id); + } + + /** + * A new P2PConnection is established and can be used for sending + * and receivong apckages. + * @param connection the connection + */ + public void newP2PConnection(P2PConnection connection) { + synchronized (this) { + if (connections.containsKey(connection.getRemoteAddr()) + || connectionManager.getLocalAddr().equals(connection.getRemoteAddr())) { + connection.close(); + return; + } + connections.put(connection.getRemoteAddr(), connection); + } + connection.setRouter(this); + notifyListeners(true); + } + + /** + * A connection to a neighbour was closed. + * @param connection the connection + */ + public void connectionClosed(P2PConnection connection) { + synchronized (this) { + connections.remove(connection.getRemoteAddr()); + } + notifyListeners(true); + } + + /** + * Close all connections. + */ + public void close() { + P2PConnection[] cs; + synchronized (this) { + cs = connections.values().toArray(new P2PConnection[0]); + } + for(P2PConnection c : cs) { + c.close(); + } + } + + /** + * Print the routing table. + */ + public void printTable() { + System.out.println("Routing Table (this is: "+connectionManager.getLocalAddr()+")"); + System.out.println("============="); + + synchronized (this) { + for(P2PConnection c : connections.values()) { + System.out.println( + c.getRemoteAddr()+"\t"+ + c.getConnection()); + } + } + + System.out.println(); + } + + /** + * Called when a packad arrived + * @param connection the connection which recheived this packet + * @param packet the packet + */ + public void receive(P2PConnection connection, byte[] packet) { + ByteArrayInputStream inB = new ByteArrayInputStream(packet); + + try { + int type = inB.read(); + + switch (type) { + case DATA_PACKET: + case DATA_BROADCAST_PACKET: { + handleDataPacket(type, packet); + break; + } + case ASK_DB: { + ObjectInputStream inO = new ObjectInputStream(inB); + PeerID a = (PeerID)inO.readObject(); + long hisVer = inO.readLong(); + long myVer = 0; + synchronized (this) { + VersionizedMap db = peers.get(a); + if (db!=null) { + myVer = db.getVersion(); + } + } + if (myVer>hisVer) sendDBPacket(connection, a); + break; + } + case SEND_DB: { + ObjectInputStream inO = new ObjectInputStream(inB); + PeerID a = (PeerID)inO.readObject(); + VersionizedMap hisDB = (VersionizedMap)inO.readObject(); + long myVer = 0; + synchronized (this) { + VersionizedMap db = peers.get(a); + if (db!=null) myVer = db.getVersion(); + if (myVer < hisDB.getVersion()) peers.put(a, hisDB); + } + dbChanged(a); + break; + } + case INTERNAL_PACKET: { + handleInternalPacket(packet); + break; + } + default: throw new IOException("Bad packet type"); + } + } catch (IOException e) { + Logger.getLogger("").log(Level.WARNING, "closing connection to "+connection.getRemoteAddr(), e); + connection.close(); + } catch (ClassNotFoundException e) { + Logger.getLogger("").log(Level.SEVERE, "Dying!", e); + System.exit(1); + } + } + + /** + * Handle a data packet + * @param type the type of the packet + * @param packet the packet + */ + private void handleDataPacket(int type, byte[] packet) { + MacAddress dest = new MacAddress(packet, 0+1); + + if (dest.equals(myMAC)) { + //System.out.println("Data-Packet from "+new MacAddress(packet, 6+1)+" for me"); + byte[] subPacket; + + if (type==DATA_BROADCAST_PACKET) { + subPacket = new byte[packet.length-1-6]; + System.arraycopy(packet, 1+6, subPacket, 0, subPacket.length); + } else { + subPacket = new byte[packet.length-1]; + System.arraycopy(packet, 1, subPacket, 0, subPacket.length); + } + + if (vpnConnector!=null) vpnConnector.receive(subPacket); + } else { + //System.out.println("Data-Packet from "+new MacAddress(packet, 6+1)+" for "+dest); + sendInt(dest, packet, false); + } + } + + /** + * Send an packet. + * @param dest the destination + * @param packet the packet + * @param highPriority has this packet a high priority? + */ + private void sendInt(MacAddress dest, byte[] packet, boolean highPriority) { + P2PConnection[] cs = findRoute(dest); + if (cs.length>0) { + int minI=0; + double minPing = Double.MAX_VALUE; + + for(int i=0; i macs = getKnownMACs(false); + for(MacAddress d : macs) { + byte[] parentPacket = new byte[packet.length+1+6]; + parentPacket[0] = DATA_BROADCAST_PACKET; + System.arraycopy(packet, 0, parentPacket, 1+6, packet.length); + System.arraycopy(d.getAddress(), 0, parentPacket, 1, 6); // change destination + sendInt(d, parentPacket, false); + } + } else { + byte[] parentPacket = new byte[packet.length+1]; + parentPacket[0] = DATA_PACKET; + System.arraycopy(packet, 0, parentPacket, 1, packet.length); + sendInt(mac, parentPacket, false); + } + } + + /** + * Add an internal packet listener. + * @param internalPort listen to this port + * @param l the listener + */ + public synchronized void addInternalPacketListener(byte internalPort, InternalPacketListener l) { + internalListeners.put(internalPort, l); + } + + /** + * Handle an internal packet + * @param packet the packet + */ + private void handleInternalPacket(byte[] packet) { + MacAddress dest = new MacAddress(packet, 0+2); + byte intPort = packet[1]; + + if (dest.equals(myMAC)) { + byte[] data = new byte[packet.length-2-6]; + System.arraycopy(packet, 2+6, data, 0, data.length); + + InternalPacketListener l; + synchronized (this) { + l = internalListeners.get(intPort); + } + if (l!=null) l.receiveInternalPacket(this, intPort, data); + } else { + sendInt(dest, packet, intPort<0); + } + } + + /** + * Send an internal packet + * @param to the destination + * @param internalPort the internal destination port + * @param data the data + */ + public void sendInternalPacket(MacAddress to, byte internalPort, byte[] data) { + if (to==null) { + Collection macs = getKnownMACs(false); + for(MacAddress d : macs) { + if (!d.equals(myMAC)) sendInternalPacket(d, internalPort, data); + } + } else { + byte[] packet = new byte[1 + 1 + 6 + data.length]; + packet[0] = INTERNAL_PACKET; + packet[1] = internalPort; + System.arraycopy(to.getAddress(), 0, packet, 2, 6); + System.arraycopy(data, 0, packet, 1+1+6, data.length); + sendInt(to, packet, internalPort<0); + } + } + + @Override + public void tableChanged(Router router) { + printTable(); + } + + public void setVpnConnector(VPNConnector vpnConnector) { + this.vpnConnector = vpnConnector; + } + + public MacAddress getMyMAC() { + return myMAC; + } +} diff --git a/src/org/p2pvpn/network/RoutungTableListener.java b/src/org/p2pvpn/network/RoutungTableListener.java new file mode 100644 index 0000000..58fe7c4 --- /dev/null +++ b/src/org/p2pvpn/network/RoutungTableListener.java @@ -0,0 +1,32 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; + +/** + * A listener which is notified, when a the list of peers changed. + * @author Wolfgang Ginolas + */ +public interface RoutungTableListener { + /** + * Called when the list of peers or the distibuted database changed. + * @param router the Router + */ + public void tableChanged(Router router); +} diff --git a/src/org/p2pvpn/network/TCPConnection.java b/src/org/p2pvpn/network/TCPConnection.java new file mode 100644 index 0000000..cdde16a --- /dev/null +++ b/src/org/p2pvpn/network/TCPConnection.java @@ -0,0 +1,348 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; +import org.p2pvpn.network.bandwidth.MeasureBandwidth; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.security.InvalidKeyException; +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import org.p2pvpn.tools.CryptoUtils; + +/** + * This is the lowest layer in the P2PVPN network. It encrypts packages and + * sends and recheives them using TCP. + * @author Wolfgang Ginolas + */ +public class TCPConnection implements Runnable { + + private static final double BUCKET_TIME = 0.5; + private static final int BUCKET_LEN = 10; + + public static final int DEFAULT_MAX_QUEUE = 10; + public static final boolean DEFAULT_TCP_FLUSH = false; + + private static final int MAX_PACKET_SIZE = 10 * 1024; + + private enum CCState {WAIT_FOR_IV, WAIT_FOR_DATA}; + + private MeasureBandwidth bwIn, bwOut; // The currently used Bandwidth + + private Cipher cIn, cOut; // The ciphers for sending and receiving + private SecretKey key; // The current encryption kay + private CCState state; // The state of this connection + + private ConnectionManager connectionManager;// The ConnectionManager + private Socket socket; // the Socket for this connection + private InputStream in; // InputStream for this connection + private BufferedOutputStream out; // OutputStream for this connection + private SocketAddress peer; // the remote address + private P2PConnection listener; // the upper network layer + + private Queue sendQueue; // a send queue + private boolean closed; // is this connection closed? + + private long lastActive; // time of the last received packet + + /** + * Create a new TCPConnection + * @param connectionManager the ConnectionManager + * @param socket the Socket of the connection + * @param keyBytes the encryption kay to use + */ + public TCPConnection(ConnectionManager connectionManager, Socket socket, byte[] keyBytes) { + this.connectionManager = connectionManager; + this.socket = socket; + peer = socket.getRemoteSocketAddress(); + sendQueue = new LinkedList(); + closed = false; + cIn = null; + cOut = null; + bwIn = new MeasureBandwidth(BUCKET_TIME, BUCKET_LEN); + bwOut = new MeasureBandwidth(BUCKET_TIME, BUCKET_LEN); + state = CCState.WAIT_FOR_DATA; + lastActive = System.currentTimeMillis(); + + try { + in = socket.getInputStream(); + out = new BufferedOutputStream(socket.getOutputStream()); + changeKey(keyBytes); + this.connectionManager.newConnection(this); + (new Thread(this, "TCPConnection "+peer)).start(); + (new Thread(new Runnable() { + public void run() { + sendThread(); + } + }, "TCPConnection.sendThread "+peer)).start(); + } catch (IOException e) { + Logger.getLogger("").log(Level.WARNING, "", e); + } + } + + /** + * Change the encryption key. + * @param keyBytes the new key + */ + public void changeKey(byte[] keyBytes) { + state = CCState.WAIT_FOR_IV; + + key = CryptoUtils.decodeSymmetricKey(keyBytes); + Cipher newOut = CryptoUtils.getSymmetricCipher(); + try { + newOut.init(Cipher.ENCRYPT_MODE, key); + } catch (InvalidKeyException ex) { + Logger.getLogger("").log(Level.SEVERE, null, ex); + close(); + } + sendEncypted(newOut.getIV(), true); + + cOut = newOut; + } + + /** + * Read an 2 Byte integer from the connection + * @return the int + * @throws java.io.IOException + */ + private int readInt() throws IOException { + int result, high, low; + high = in.read(); + if (high==-1) throw new IOException("Connection to "+peer+" lost"); + low = in.read(); + if (low==-1) throw new IOException("Connection to "+peer+" lost"); + result = (high << 8) + low; + return result; + } + + /** + * Receive packages. + */ + @Override + public void run() { + byte[] buffer = new byte[MAX_PACKET_SIZE]; + try { + while (true) { + int size = readInt(); + + if (size>MAX_PACKET_SIZE) throw new IOException("Packet too large"); + + int rest=size; + int off=0; + + while(rest>0) { + int len = in.read(buffer, off, rest); + if (len==-1) throw new IOException("Connection to "+peer+" lost"); + rest -= len; + off += len; + } + + byte[] packet = new byte[size]; + System.arraycopy(buffer, 0, packet, 0, size); + handleEncryptedPacket(packet); + } + } catch (Throwable e) { + //e.printStackTrace(); + } + + if (listener!=null) listener.connectionClosed(); + closed = true; + + synchronized (sendQueue) {sendQueue.notify();} + + try { + socket.close(); + } catch (IOException e) { + Logger.getLogger("").log(Level.WARNING, "", e); + } + } + + /** + * Get packages from the queue and send them. + */ + private void sendThread() { + try { + while (true) { + if (closed) break; + byte[] packet; + synchronized (sendQueue) { + packet = sendQueue.poll(); + } + if (packet == null) { + out.flush(); + try { + synchronized (sendQueue) {sendQueue.wait();} + } catch (InterruptedException ex) { + } + } + if (packet != null) { + sendEncypted(packet, false); + if (connectionManager.isTCPFlush()) out.flush(); + } + } + } catch (IOException iOException) { + //Logger.getLogger("").log(Level.SEVERE, null, iOException); + close(); + } + } + + /** + * Encrypt an packet and send it. + * @param packet the packet + * @param flush flush the stream? + */ + private void sendEncypted(byte[] packet, boolean flush) { + if (cOut==null) { + sendToSocket(packet, flush); + } else { + try { + sendToSocket(cOut.doFinal(packet), flush); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + close(); + } + } + } + + /** + * Send an packet throug the socket. + * @param packet the packet + * @param flush flush the stream? + */ + private void sendToSocket(byte[] packet, boolean flush) { + try { + connectionManager.getSendLimit().waitForTokens(2+packet.length); + + int high = (packet.length & 0xFF00) >> 8; + int low = packet.length & 0xFF; + out.write(high); + out.write(low); + out.write(packet); + if (flush) out.flush(); + bwOut.countPacket(2+packet.length); + } catch (IOException iOException) { + close(); + } + } + + /** + * Handle an incoming encrypten packet. + * @param packet the packet + */ + public void handleEncryptedPacket(byte[] packet) { + byte[] ct; + + lastActive = System.currentTimeMillis(); + bwIn.countPacket(2+packet.length); + if (!connectionManager.getRecLimit().tokensAvailable(2+packet.length)) { + return; // drop packet to limit bandwidth + } + + if (cIn==null) { + ct = packet; + } else { + try { + ct = cIn.doFinal(packet); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + close(); + return; + } + } + switch (state) { + case WAIT_FOR_IV: + cIn = CryptoUtils.getSymmetricCipher(); + try { + cIn.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ct)); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + close(); + } + state = CCState.WAIT_FOR_DATA; + break; + case WAIT_FOR_DATA: + if (listener!=null) listener.receive(ct); + break; + } + } + + /** + * Set the object of the upperlayer. + * @param listener the upper layer + */ + public void setListener(P2PConnection listener) { + this.listener = listener; + } + + /** + * Put a packet in the sen queue. + * @param packet the packet + * @param highPriority a high priority packet? A high + * priority packer won't be dropped even if the send queue is full. + */ + public void send(byte[] packet, boolean highPriority) { + synchronized (sendQueue) { + if (highPriority || sendQueue.size(). +*/ + +package org.p2pvpn.network; + +/** + * This was an attempt to penetrate NAT with UpNP. Currently not used. + * @author Wolfgang Ginolas + */ +public class UPnPPortForward { + +} + +/* +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.sbbi.upnp.Discovery; +import net.sbbi.upnp.impls.InternetGatewayDevice; + + +public class UPnPPortForward implements Runnable { + + private static final long UPDATE_S = 10*60; + private static final int LEASEDURATION_S = 0; + private static final int DISCOVERY_TIMEOUT_MS = 5 * 1000; + + ConnectionManager connectionManager; + + private Vector listeners; + + private InternetGatewayDevice igd; + private String externalIP; + private boolean mapped; + private String error; + + public UPnPPortForward(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + listeners = new Vector(); + + connectionManager.getScheduledExecutor().schedule(this, 1, TimeUnit.SECONDS); + } + + private InternetGatewayDevice checkInterface(NetworkInterface iface) throws IOException { + InternetGatewayDevice[] igds = InternetGatewayDevice.getDevices( + DISCOVERY_TIMEOUT_MS, Discovery.DEFAULT_TTL, Discovery.DEFAULT_MX, iface); + if (igds!=null && igds.length>0) { + return igds[0]; + } else { + return null; + } + } + + public void run() { + igd = null; + mapped = false; + error = null; + externalIP = null; + NetworkInterface iface = null; + + try { + Enumeration ifs = NetworkInterface.getNetworkInterfaces(); + while (ifs.hasMoreElements() && igd == null) { + NetworkInterface i = ifs.nextElement(); + InternetGatewayDevice cigd = null; + try { + cigd = checkInterface(i); + } catch (IOException ex) { + } + if (cigd != null) { + igd = cigd; + iface = i; + } + } + + if (igd!=null) { + Enumeration ips = iface.getInetAddresses(); + String myIP = null; + while (ips.hasMoreElements()) { + InetAddress ip = ips.nextElement(); + if (ip instanceof Inet4Address) { + myIP = ip.getHostAddress(); + } + } + if (myIP!=null) { + int port = connectionManager.getServerPort(); + mapped = igd.addPortMapping("P2PVPN", null, port, port, myIP, LEASEDURATION_S, "TCP"); + } + } + + + } catch (Throwable t) { + error = t.getMessage(); + Logger.getLogger("").log(Level.WARNING, "UPnP error", t); + } + + updateListeners(); + connectionManager.getScheduledExecutor().schedule(this, UPDATE_S, TimeUnit.SECONDS); + } + + private void updateListeners() { + synchronized (listeners) { + for(UPnPPortForwardListener l : listeners) { + try { + l.upnpChanged(this); + } catch (Throwable t) { + Logger.getLogger("").log(Level.WARNING, "", t); + } + } + } + } + + public void addListener(UPnPPortForwardListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + public void removeListener(UPnPPortForwardListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + public String getError() { + return error; + } + + public String getExternalIP() { + return externalIP; + } + + public InternetGatewayDevice getIgd() { + return igd; + } + + public boolean isMapped() { + return mapped; + } + + +} +*/ \ No newline at end of file diff --git a/src/org/p2pvpn/network/UPnPPortForwardListener.java b/src/org/p2pvpn/network/UPnPPortForwardListener.java new file mode 100644 index 0000000..3da159b --- /dev/null +++ b/src/org/p2pvpn/network/UPnPPortForwardListener.java @@ -0,0 +1,28 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; + +/** + * This was an attempt to penetrate NAT with UpNP. Currently not used. + * @author Wolfgang Ginolas + */ +public interface UPnPPortForwardListener { + public void upnpChanged(UPnPPortForward upnp); +} diff --git a/src/org/p2pvpn/network/VPNConnector.java b/src/org/p2pvpn/network/VPNConnector.java new file mode 100644 index 0000000..d6a4b28 --- /dev/null +++ b/src/org/p2pvpn/network/VPNConnector.java @@ -0,0 +1,156 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network; + +import org.p2pvpn.tuntap.TunTap; + +/** + * This claas establishes a connection between the virtual network adapter + * and the Router. + * @author wolfgang + */ +public class VPNConnector implements Runnable { + + private final static byte IPV4_HIGH = 0x08; + private final static byte IPV4_LOW = 0x00; + private final static byte IPV4_UDP = 17; + + private TunTap tuntap; + private Router router; + private Thread myThread; + + private static VPNConnector vpnConnector = null; + + /** + * Create a new VPNConnector. + * @throws java.lang.Exception + */ + private VPNConnector() throws Exception { + tuntap = TunTap.createTunTap(); + router = null; + + myThread = new Thread(this, "VPNConnector"); + myThread.start(); + } + + /** + * Get the global VPNConnector. + * @return + * @throws java.lang.Exception + */ + public static VPNConnector getVPNConnector() throws Exception { + if (vpnConnector == null) vpnConnector = new VPNConnector(); + return vpnConnector; + } + + /** + * Set the Router. + * @param router the Router. + */ + public void setRouter(Router router) { + this.router = router; + if (router!=null) router.setVpnConnector(this); + } + + public TunTap getTunTap() { + return tuntap; + } + + /** + * Send an packet to the virtual network adapter. + * @param packet the packet + */ + public void receive(byte[] packet) { + //System.out.println("VPNConnector.write "+packet.length); + tuntap.write(packet, packet.length); + } + + /*public void close() { + tuntap.close(); + myThread.interrupt(); + }*/ + +/* Headers of a MAC-Packet + * + * Offset + * 0: Ethernet + * 14: IP + * 34: UDP +*/ + + /** + * Force the correct local IP in an UDP broadcast packet. This is necessary + * becaus Windows sometimes uses the wrong sourc IP in breadcast packages. + * @param packet the packet + */ + private void forceIP (byte[] packet) { + if (packet.length>= 14+20) { + if (packet[12]==IPV4_HIGH && packet[13]==IPV4_LOW && packet[14+9]==IPV4_UDP) { // is this IPv4 and UDP? + byte[] ip = tuntap.getIPBytes(); + if (packet[26] != ip[0] || packet[27] != ip[1] || + packet[28] != ip[2] || packet[29] != ip[3]) { + + int checksum = 0; + packet[14+10] = 0; // set checksum = 0 + packet[14+11] = 0; + System.arraycopy(ip, 0, packet, 26, 4); // replace the source ip + + for(int i=14; i<34; i+=2) { + checksum += ((0xFF&packet[i]) << 8) + (0xFF&packet[i+1]); + } + + while ((checksum & 0xFFFF0000) != 0) { + checksum = (checksum & 0xFFFF) + (checksum >> 16); + } + + checksum = ~checksum; + + packet[14+10] = (byte)(0xFF & (checksum >> 8)); // set the new IP header chacksum + packet[14+11] = (byte)(0xFF & checksum); + + packet[14+20+6] = 0; // unset UDP checksum + packet[14+20+7] = 0; + + } + } + } + } + + + /** + * A thread the reads packages from the virtual network adapter and sends them + * to the Router. + */ + @Override + public void run() { + byte[] buffer = new byte[2048]; + // TODO close? + while(true) { + int len = tuntap.read(buffer); + //System.out.println("VPNConnector.read "+len); + if (len>=12) { + byte[] packet = new byte[len]; + System.arraycopy(buffer, 0, packet, 0, len); + forceIP(packet); + if (router!=null) router.send(packet); + } + } + } +} diff --git a/src/org/p2pvpn/network/bandwidth/MeasureBandwidth.java b/src/org/p2pvpn/network/bandwidth/MeasureBandwidth.java new file mode 100644 index 0000000..0ea7dd4 --- /dev/null +++ b/src/org/p2pvpn/network/bandwidth/MeasureBandwidth.java @@ -0,0 +1,83 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bandwidth; + +/** + * This class can measure the bandwidth of a connection. + * @author Wolfgang Ginolas + */ +public class MeasureBandwidth { + private long bucketTime; + private int bucketLen; + private int currentBucket; + private long lastShift; + private SlidingAverage avg; + + + /** + * Create a new MeasureBandwidth + * @param bucketTime number of steps that are used for the average + * @param bucketLen the time for one step. bucketTime*bucketLen gives the time of the sliding average + */ + public MeasureBandwidth(double bucketTime, int bucketLen) { + this.bucketTime = (long)(bucketTime*1000); + this.bucketLen = bucketLen; + + avg = new SlidingAverage(bucketLen, 0); + + currentBucket = 0; + lastShift = System.currentTimeMillis(); + } + + /** + * Check if the buckets need to be shifted. + */ + private void shift() { + long time = System.currentTimeMillis(); + int cnt = 0; + while ( + lastShift + bucketTime < time) { + avg.putVaule(currentBucket); + currentBucket = 0; + lastShift += bucketTime; + + if (cnt>bucketLen) lastShift = time; + cnt++; + } + } + + /** + * Count bytes that were just received/send. + * @param size nimber of bytes + */ + public void countPacket(int size) { + shift(); + currentBucket += size; + } + + /** + * Return the current average bandwidth. + * @return the bandwidth in bytes/s + */ + public double getBandwidth() { + shift(); + return avg.getAverage() / bucketTime * 1000; + } +} diff --git a/src/org/p2pvpn/network/bandwidth/SlidingAverage.java b/src/org/p2pvpn/network/bandwidth/SlidingAverage.java new file mode 100644 index 0000000..cdc6177 --- /dev/null +++ b/src/org/p2pvpn/network/bandwidth/SlidingAverage.java @@ -0,0 +1,61 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bandwidth; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * A claas that cna calculate a liding average. + * @author Wolfgang Ginolas + */ +public class SlidingAverage { + private int bucketLen; + private Queue buckets; + private double bucketSum; + + /** + * Create a new Sliding average. + * @param bucketLen number of values that are used for the average + * @param init initialisation value + */ + public SlidingAverage(int bucketLen, double init) { + this.bucketLen = bucketLen; + + buckets = new LinkedList(); + for(int i=0; i. +*/ + +package org.p2pvpn.network.bandwidth; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class can be used to limit bandwidth using the token bucket algorithm. + * @author Wolfgang Ginolas + */ +public class TokenBucket { + + private static final double MIN_WAIT_S = 0.005; + private static final double MAX_WAIT_S = 0.1; + + private static final long TIMEOUT = 1000; + + private double bandwidth; + private double bucketSize; + + private double bucket; + private long lastFill; + + /** + * Create a new TokenBicket + * @param bandwidth the maximum andwith in tokens/s + * @param bucketSize the maximum burst size + */ + public TokenBucket(double bandwidth, double bucketSize) { + this.bandwidth = bandwidth; + this.bucketSize = bucketSize; + + bucket = 0; + lastFill = System.currentTimeMillis(); + } + + /** + * Update the bucket fill level. + */ + private synchronized void updateBucket() { + long time = System.currentTimeMillis(); + + if (bandwidth==0) { + bucket = bucketSize; + } else { + bucket += bandwidth * (time-lastFill) / 1000; + if (bucket > bucketSize) bucket = bucketSize; + } + lastFill = time; + } + + /** + * Wait until this many tokens may be send/received. + * @param tokens number if tokens + */ + public void waitForTokens(double tokens) { + while (true) { + updateBucket(); + synchronized (this) { + if (bucket>=0) break; + } + double waitTime = -bucket / bandwidth; + if (waitTime < MIN_WAIT_S || waitTime > MAX_WAIT_S) waitTime = MIN_WAIT_S; + try { + Thread.sleep((long) (waitTime*1000)); + } catch (InterruptedException ex) { + Logger.getLogger(TokenBucket.class.getName()).log(Level.SEVERE, null, ex); + } + } + synchronized (this) { + bucket -= tokens; + } + } + + /** + * Check if the number of tokens may be send/received right now. + * @param tokens number of tokens + * @return send/received allowed right now? + */ + public boolean tokensAvailable(double tokens) { + updateBucket(); + synchronized (this) { + if (bucket>=0) { + bucket -= tokens; + return true; + } else { + return false; + } + } + } + + /** + * Set the maximum bandwidth. + * @param bandwidth the bandwidth in tokens/s + */ + public synchronized void setBandwidth(double bandwidth) { + this.bandwidth = bandwidth; + } +} diff --git a/src/org/p2pvpn/network/bittorrent/BitTorrentTracker.java b/src/org/p2pvpn/network/bittorrent/BitTorrentTracker.java new file mode 100644 index 0000000..2210ccc --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/BitTorrentTracker.java @@ -0,0 +1,143 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent; + +import org.p2pvpn.network.bittorrent.bencode.BencodeString; +import org.p2pvpn.network.bittorrent.bencode.Bencode; +import org.p2pvpn.network.*; +import java.io.IOException; +import java.io.PushbackInputStream; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.MessageDigest; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.commons.codec.net.URLCodec; +import org.p2pvpn.network.bittorrent.bencode.BencodeInt; +import org.p2pvpn.tools.CryptoUtils; + +/** + * This class connects to a BitTorrent tracker, to find other peers. + * (http://www.bittorrent.org/beps/bep_0003.html) + * @author Wolfgang Ginolas + */ +public class BitTorrentTracker implements Runnable { + private static final int REFRESH_S = 10 * 60; + + ConnectionManager connectionManager; + String tracker; + byte[] peerId; + + /** + * Create a new BitTorrentTracker object which periodically polls an + * tracker to find other peers. + * @param connectionManager the ConnectionManager + * @param tracker the trakcer url + */ + public BitTorrentTracker(ConnectionManager connectionManager, String tracker) { + this.connectionManager = connectionManager; + this.tracker = tracker; + peerId = new byte[20]; + new Random().nextBytes(peerId); + schedule(1); + } + + /** + * Schedule a tracker poll + * @param seconds poll in secongs seconds + */ + private void schedule(int seconds) { + connectionManager.getScheduledExecutor().schedule(this, seconds, TimeUnit.SECONDS); + } + + /** + * Poll the tracker. + * @param hash the hash of the cuttent network + * @param port the local port + * @return a Bencode-Map + * @throws java.net.MalformedURLException + * @throws java.io.IOException + */ + private Map trackerRequest(byte[] hash, int port) throws MalformedURLException, IOException { + String sUrl = tracker + "?info_hash=" + new String(new URLCodec().encode(hash)) + + "&port=" + port + "&compact=1&peer_id=" + new String(new URLCodec().encode(peerId)) + + "&uploaded=0&downloaded=0&left=100"; + + //System.out.println(sUrl); + + URL url = new URL(sUrl); + PushbackInputStream in = new PushbackInputStream(url.openStream()); + return (Map) Bencode.parseBencode(in); + } + + /** + * Calculate a hash for the network, using the pubkicKey of the net + * @param maxLen length of the hash + * @return the hash + */ + private byte[] networkHash(int maxLen) { + byte[] b = connectionManager.getAccessCfg().getPropertyBytes("network.signature", null); + MessageDigest md = CryptoUtils.getMessageDigest(); + md.update("BitTorrent".getBytes()); // make sure the key differs from + // other hashes created from the publicKey + byte[] hash = md.digest(b); + byte[] result = new byte[Math.min(maxLen, hash.length)]; + System.arraycopy(hash, 0, result, 0, result.length); + return result; + } + + /** + * Poll the tracker and add the returned IPs to the known hosts list. + */ + public void run() { + int nextRequest = REFRESH_S; + try { + Map res = trackerRequest(networkHash(20), connectionManager.getServerPort()); + + BencodeInt minInterval = (BencodeInt)res.get(new BencodeString("min interval")); + if (minInterval!=null) nextRequest = minInterval.getInt(); + + byte[] peers = ((BencodeString)res.get(new BencodeString("peers"))).getBytes(); + + for (int i=0; i. +*/ + +package org.p2pvpn.network.bittorrent; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnknownHostException; + +public class Contact { + public final static int MAX_BAD = 10; + + private BigInteger id; + private SocketAddress addr; + + public static InetSocketAddress parseSocketAddress(byte[] bs, int off, int len) { + if (len==4+2 || len==16+2) { + int ipLen = len-2; + byte[] ipa = new byte[ipLen]; + System.arraycopy(bs, off, ipa, 0, ipLen); + InetAddress ip = null; + try { + ip = InetAddress.getByAddress(ipa); + } catch (UnknownHostException ex) { + ex.printStackTrace(); + } + int port = ((0xff&bs[off+ipLen]) << 8) + (0xff&bs[off+ipLen+1]); + return new InetSocketAddress(ip, port); + } else return null; + } + + public Contact(BigInteger id, SocketAddress addr) { + this.id = id; + this.addr = addr; + } + + public Contact(byte[] idS, SocketAddress addr) { + this(DHT.unsigned(new BigInteger(idS)), addr); + } + + public Contact(byte[] bs, int off, int len) { + byte[] id = new byte[20]; + System.arraycopy(bs, off, id, 0, 20); + this.id = DHT.unsigned(new BigInteger(id)); + this.addr = parseSocketAddress(bs, off+20, len-20); + } + + public SocketAddress getAddr() { + return addr; + } + + public BigInteger getId() { + return id; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Contact other = (Contact) obj; + if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 67 * hash + (this.id != null ? this.id.hashCode() : 0); + return hash; + } + + @Override + public String toString() { + return "("+id+", "+addr+")"; + } +} diff --git a/src/org/p2pvpn/network/bittorrent/DHT.java b/src/org/p2pvpn/network/bittorrent/DHT.java new file mode 100644 index 0000000..7d2501d --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/DHT.java @@ -0,0 +1,288 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ +package org.p2pvpn.network.bittorrent; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; +import java.util.concurrent.PriorityBlockingQueue; +import org.p2pvpn.network.bittorrent.bencode.Bencode; +import org.p2pvpn.network.bittorrent.bencode.BencodeInt; +import org.p2pvpn.network.bittorrent.bencode.BencodeList; +import org.p2pvpn.network.bittorrent.bencode.BencodeMap; +import org.p2pvpn.network.bittorrent.bencode.BencodeObject; +import org.p2pvpn.network.bittorrent.bencode.BencodeString; + +public class DHT { + private static final int PACKET_LEN = 10*1024; + private static final BigInteger MASK = new BigInteger("1").shiftLeft(160); + private static int QUEUE_MAX_LEN = 100; + private static int MAX_BAD = 4; + + private DatagramSocket dSock; + + private BencodeString id = new BencodeString("01234567890123456789"); + private BencodeString searchID = new BencodeString("abcdefghijabcdefghij"); + private BigInteger searchIDInt = unsigned(new BigInteger(searchID.getBytes())); + + private PriorityBlockingQueue peerQueue; + + private Map peerBad; + + public DHT(DatagramSocket dSock) { + this.dSock = dSock; + + peerQueue = new PriorityBlockingQueue(10, new Comparator() { + public int compare(Contact o1, Contact o2) { + BigInteger d1 = searchDist(o1); + BigInteger d2 = searchDist(o2); + return d1.compareTo(d2); + } + }); + + peerBad = Collections.synchronizedMap(new HashMap()); + + new Thread(new Runnable() { + public void run() { + recvThread(); + } + }).start(); + + testPing(); + } + + private BigInteger searchDist(Contact c) { + return unsigned(searchIDInt.xor(c.getId())); + } + + public static BigInteger unsigned(BigInteger i) { + if (i.signum()<0) { + return MASK.add(i); + } else return i; + } + + private void ping(SocketAddress addr) throws IOException { + BencodeMap m = new BencodeMap(); + m.put(new BencodeString("t"), new BencodeString("ping")); + m.put(new BencodeString("y"), new BencodeString("q")); + m.put(new BencodeString("q"), new BencodeString("ping")); + BencodeMap a = new BencodeMap(); + a.put(new BencodeString("id"), id); + m.put(new BencodeString("a"), a); + System.out.print("ping: "+addr); + sendPacket(addr, m); + System.out.println(" done"); + } + + private void getPeers(Contact c) throws IOException { + BencodeMap m = new BencodeMap(); + m.put(new BencodeString("t"), new BencodeString("get_peers")); + m.put(new BencodeString("y"), new BencodeString("q")); + m.put(new BencodeString("q"), new BencodeString("get_peers")); + BencodeMap a = new BencodeMap(); + a.put(new BencodeString("id"), id); + a.put(new BencodeString("info_hash"), searchID); + a.put(new BencodeString("want"), new BencodeString("n6")); + m.put(new BencodeString("a"), a); + //System.out.println("get_peers: "+c); + sendPacket(c.getAddr(), m); + } + + private void announcePeer(Contact c, BencodeString token) throws IOException { + if (token==null) return; + BencodeMap m = new BencodeMap(); + m.put(new BencodeString("t"), new BencodeString("announce")); + m.put(new BencodeString("y"), new BencodeString("q")); + m.put(new BencodeString("q"), new BencodeString("announce_peer")); + BencodeMap a = new BencodeMap(); + a.put(new BencodeString("id"), id); + a.put(new BencodeString("info_hash"), searchID); + a.put(new BencodeString("port"), new BencodeInt(dSock.getLocalPort())); + a.put(new BencodeString("token"), token); + m.put(new BencodeString("a"), a); + //System.out.println("get_peers: "+c); + sendPacket(c.getAddr(), m); + } + + private void cleanQueue() { + + } + + + + private void testPing() { + try { + while (true) { + Thread.sleep(1000); + if (peerQueue.isEmpty()) { + //ping(new InetSocketAddress("router.utorrent.com", 6881)); + //ping(new InetSocketAddress("router.torrent.com", 6881)); + ping(new InetSocketAddress("dht.wifi.pps.jussieu.fr",6881)); + } else { + Vector best = new Vector(); + { + Contact c; + while (best.size()<4 && null!=(c=peerQueue.poll())) { + if (!best.contains(c) && getBad(c). +*/ + +package org.p2pvpn.network.bittorrent; + +import java.math.BigInteger; + +public abstract class RoutingTable { + protected DHT dht; + protected BigInteger min, max; + + public RoutingTable(DHT dht, BigInteger min, BigInteger max) { + this.dht = dht; + this.min = min; + this.max = max; + } + + abstract public RoutingTableLeaf findBucket(BigInteger id); + + public Contact findContact(BigInteger id) { + for(Contact c : findBucket(id).getBucket()) { + if (c.getId().equals(id)) return c; + } + return null; + } + + abstract public RoutingTable addContact(Contact c); + abstract public RoutingTable removeContact(BigInteger id); +} diff --git a/src/org/p2pvpn/network/bittorrent/RoutingTableLeaf.java b/src/org/p2pvpn/network/bittorrent/RoutingTableLeaf.java new file mode 100644 index 0000000..9404f2c --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/RoutingTableLeaf.java @@ -0,0 +1,86 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent; + +import java.math.BigInteger; +import java.util.Vector; + +public class RoutingTableLeaf extends RoutingTable { + private static final int MAX_SIZE = 8; + + + private Vector bucket; + + public RoutingTableLeaf(DHT dht, BigInteger min, BigInteger max) { + super(dht, min, max); + this.bucket = new Vector(); + } + + private RoutingTable split() { + BigInteger center = min.add(max).divide(new BigInteger("2")); + RoutingTableLeaf low = new RoutingTableLeaf(dht, min, center); + RoutingTableLeaf high = new RoutingTableLeaf(dht, center.add(new BigInteger("1")), max); + RoutingTableNode node = new RoutingTableNode(dht, min, max, low, high); + + for (Contact c : bucket) { + node.addContact(c); + } + return node; + } + + private boolean maySplit() { + return (min.compareTo(dht.getID()) <= 0) && (dht.getID().compareTo(max) <= 0); + } + + @Override + public RoutingTable addContact(Contact c) { + int i = bucket.indexOf(c); + if (i!=-1) { + bucket.set(i, c); + return this; + } + + if (bucket.size() < MAX_SIZE) { + bucket.add(c); + return this; + } + + if (maySplit()) { + RoutingTable s = split(); + s.addContact(c); + return s; + } + return this; + } + + @Override + public RoutingTableLeaf findBucket(BigInteger id) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public RoutingTable removeContact(BigInteger id) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public Vector getBucket() { + return bucket; + } +} diff --git a/src/org/p2pvpn/network/bittorrent/RoutingTableNode.java b/src/org/p2pvpn/network/bittorrent/RoutingTableNode.java new file mode 100644 index 0000000..bb69e74 --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/RoutingTableNode.java @@ -0,0 +1,59 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent; + +import java.math.BigInteger; + +public class RoutingTableNode extends RoutingTable { + + private RoutingTable low, high; + BigInteger center; + + public RoutingTableNode(DHT dht, BigInteger min, BigInteger max, RoutingTable low, RoutingTable high) { + super(dht, min, max); + this.low = low; + this.high = high; + this.center = min.add(max).divide(new BigInteger("2")); + } + + + @Override + public RoutingTable addContact(Contact c) { + if (c.getId().compareTo(dht.getID()) <= 0) + low = low.addContact(c); + else high = high.addContact(c); + return this; + } + + @Override + public RoutingTableLeaf findBucket(BigInteger id) { + if (id.compareTo(dht.getID()) <= 0) + return low.findBucket(id); + else return high.findBucket(id); + } + + @Override + public RoutingTable removeContact(BigInteger id) { + if (id.compareTo(dht.getID()) <= 0) + return low.removeContact(id); + else return high.removeContact(id); + } + +} diff --git a/src/org/p2pvpn/network/bittorrent/bencode/Bencode.java b/src/org/p2pvpn/network/bittorrent/bencode/Bencode.java new file mode 100644 index 0000000..52216bb --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/bencode/Bencode.java @@ -0,0 +1,171 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent.bencode; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; + +public class Bencode { + + /** + * Parse a Bencode string + * @param in the input stream + * @return the result. The type is Integer, BencodeString, + * Vector<Object> or HashMap<Object, Object> + * @throws java.io.IOException + */ + static public BencodeObject parseBencode(InputStream in) throws IOException { + return parseBencode(new PushbackInputStream(in)); + } + + /** + * Parse a Bencode string + * @param in the input stream + * @return the result. The type is Integer, BencodeString, + * Vector<Object> or HashMap<Object, Object> + * @throws java.io.IOException + */ + static public BencodeObject parseBencode(PushbackInputStream in) throws IOException { + int first = in.read(); + in.unread(first); + + switch (first) { + case 'i': + return parseBencodeInt(in); + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return parseBencodeString(in); + + case 'l': + return parseBencodeList(in); + + case 'd': + return parseBencodeMap(in); + + default: + throw new IOException("no bencode: illecal char: "+ ((char)first)); + } + } + + /** + * Parse an Mencode integer. + * @param in the inputstream + * @return the Integer + * @throws java.io.IOException + */ + static private BencodeObject parseBencodeInt(PushbackInputStream in) throws IOException { + parseBencodeExpect(in, 'i'); + return new BencodeInt(parseBencodeReadInt(in)); + } + + /** + * Read an Integer from the stream + * @param in the input stream + * @return the int + * @throws java.io.IOException + */ + static private int parseBencodeReadInt(PushbackInputStream in) throws IOException { + int result=0; + + while (true) { + int b=in.read(); + + if (b<'0' || b>'9') break; + + result = result * 10 + (b-'0'); + } + return result; + } + + /** + * Parse an BencodeString + * @param in the inputstream + * @return the BencodeString + * @throws java.io.IOException + */ + static private BencodeObject parseBencodeString(PushbackInputStream in) throws IOException { + int len = parseBencodeReadInt(in); + + byte[] bs = new byte[len]; + int pos = 0; + + while(pos. +*/ + +package org.p2pvpn.network.bittorrent.bencode; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * @author wolfgang + */ +public class BencodeInt implements BencodeObject { + int i; + + public BencodeInt(int i) { + this.i = i; + } + + public int getInt() { + return i; + } + + public void write(OutputStream out) throws IOException { + out.write('i'); + out.write(Integer.toString(i).getBytes()); + out.write('e'); + } + + @Override + public String toString() { + return Integer.toString(i); + } +} diff --git a/src/org/p2pvpn/network/bittorrent/bencode/BencodeList.java b/src/org/p2pvpn/network/bittorrent/bencode/BencodeList.java new file mode 100644 index 0000000..db1c7fa --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/bencode/BencodeList.java @@ -0,0 +1,54 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent.bencode; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Vector; + +public class BencodeList extends Vector implements BencodeObject { + + public BencodeList() { + super(); + } + + public void write(OutputStream out) throws IOException { + out.write('l'); + for (BencodeObject o : this) { + o.write(out); + } + out.write('e'); + } + + @Override + public synchronized String toString() { + StringBuffer result = new StringBuffer(); + boolean first = true; + + result.append('('); + for (BencodeObject o : this) { + if (!first) result.append(", "); + result.append(o.toString()); + first = false; + } + result.append(')'); + return super.toString(); + } +} diff --git a/src/org/p2pvpn/network/bittorrent/bencode/BencodeMap.java b/src/org/p2pvpn/network/bittorrent/bencode/BencodeMap.java new file mode 100644 index 0000000..a13fdb6 --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/bencode/BencodeMap.java @@ -0,0 +1,56 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent.bencode; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map.Entry; + +public class BencodeMap extends HashMap implements BencodeObject { + + public BencodeMap() { + super(); + } + + public void write(OutputStream out) throws IOException { + out.write('d'); + for (Entry e : this.entrySet()) { + e.getKey().write(out); + e.getValue().write(out); + } + out.write('e'); + } + + @Override + public synchronized String toString() { + StringBuffer result = new StringBuffer(); + boolean first = true; + + result.append('('); + for (Entry e : this.entrySet()) { + if (!first) result.append(", "); + result.append(e.getKey()+":"+e.getValue()); + first = false; + } + result.append(')'); + return super.toString(); + } +} diff --git a/src/org/p2pvpn/network/bittorrent/bencode/BencodeObject.java b/src/org/p2pvpn/network/bittorrent/bencode/BencodeObject.java new file mode 100644 index 0000000..bbd5e80 --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/bencode/BencodeObject.java @@ -0,0 +1,27 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent.bencode; + +import java.io.IOException; +import java.io.OutputStream; + +public interface BencodeObject { + public void write(OutputStream out) throws IOException; +} diff --git a/src/org/p2pvpn/network/bittorrent/bencode/BencodeString.java b/src/org/p2pvpn/network/bittorrent/bencode/BencodeString.java new file mode 100644 index 0000000..c97c476 --- /dev/null +++ b/src/org/p2pvpn/network/bittorrent/bencode/BencodeString.java @@ -0,0 +1,63 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.network.bittorrent.bencode; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A byte array that can easily convertet to/from a String. + */ +public class BencodeString implements BencodeObject { + byte[] bytes; + + public BencodeString(byte[] bytes) { + this.bytes = bytes; + } + + public BencodeString(String s) { + bytes = s.getBytes(); + } + + public byte[] getBytes() { + return bytes; + } + + @Override + public boolean equals(Object obj) { + return toString().equals(obj.toString()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override + public String toString() { + return new String(bytes); + } + + public void write(OutputStream out) throws IOException { + out.write(Integer.toString(bytes.length).getBytes()); + out.write(':'); + out.write(bytes); + } +} \ No newline at end of file diff --git a/src/org/p2pvpn/tools/AdapterManager.java b/src/org/p2pvpn/tools/AdapterManager.java new file mode 100644 index 0000000..4f46d95 --- /dev/null +++ b/src/org/p2pvpn/tools/AdapterManager.java @@ -0,0 +1,115 @@ +package org.p2pvpn.tools; + + +import java.io.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; + +/** + * + * @author steve.kliebisch + */ +public class AdapterManager { + + private String arch = getArch(); + private String path = System.getProperty("user.dir"); + + private String driverFolder = path+"\\driver\\win"+arch+"\\"; + private String driverInstaller = "tapinstall.exe"; + private String driverFile = "OemWin2k.inf"; + private String driverName = "tapoas"; + + private Integer adapterNumber = 0; + + public Boolean check(){ + BufferedReader in; + String text; + + try { + String[] cmd = { + driverFolder+driverInstaller, + "find", + driverName + }; + Logger.getLogger("").log(Level.INFO, "Check adapter: " + cmd); + Process f = Runtime.getRuntime().exec(cmd); + in = new BufferedReader( new InputStreamReader( f.getInputStream()) ); + while ( (text = in.readLine() ) != null) { + if( text.startsWith("ROOT\\NET\\") ){ + Logger.getLogger("").log(Level.INFO, "Found adapter: "+text); + adapterNumber++; + } + } + f.waitFor(); + } catch (Exception e) { Logger.getLogger("").log(Level.WARNING, "Could not check adapter", e); } + + if(adapterNumber > 0) { + return true; + } else { + Logger.getLogger("").log(Level.WARNING, "No adapter found"); + return false; + } + } + + public Boolean install() { + BufferedReader i; + String text; + Boolean done = false; + Logger.getLogger("").log(Level.INFO, "arch: " + getArch() ); + Boolean install = (JOptionPane.YES_OPTION == + JOptionPane.showConfirmDialog(null, + "Install a new Tap-Win32 Adapter ?", "Adapter Install", + JOptionPane.YES_NO_OPTION)); + + if(install) + { + try { + //String[] cmd = {"cmd", "/c", "start", "/D", path+"\\driver\\", "/B", "add_adapter.bat"}; + + String[] cmd = { + driverFolder+driverInstaller, + "install", + driverFolder+driverFile, + driverName + }; + Process f = Runtime.getRuntime().exec(cmd); + i = new BufferedReader( new InputStreamReader( f.getInputStream()) ); + while ( ( text = i.readLine() ) != null ) { + Logger.getLogger("").log(Level.INFO, text); + if( text.startsWith("Driver installed") ){ + done = true; + } + } + f.waitFor(); + } catch (Exception e) { + Logger.getLogger("").log(Level.WARNING, "Could not install adapter", e); + return false; + } + } + return (done) ? true : false; + } + + public Boolean remove() { + Logger.getLogger("").log(Level.INFO, "try to remove Virtual Ethernet Adapter"); + try { + String[] cmd = { + driverFolder+driverInstaller, + "remove", + driverName + }; + Process f = Runtime.getRuntime().exec(cmd); + f.waitFor(); + return true; + } catch (Exception e) { + Logger.getLogger("").log(Level.WARNING, "Could not remove adapter", e); + return false; + } + } + + private String getArch(){ + return (new File("C:/Program Files (x86)").exists()) ? "64" : "32"; + } + + +} diff --git a/src/org/p2pvpn/tools/AdvProperties.java b/src/org/p2pvpn/tools/AdvProperties.java new file mode 100644 index 0000000..c9a5f81 --- /dev/null +++ b/src/org/p2pvpn/tools/AdvProperties.java @@ -0,0 +1,258 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.tools; + +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.commons.codec.binary.Base64; + +/** + * Extended Properties. This class allows: Storing long byte arrays, + * signing etc. + * @author Wolfgang Ginolas + */ +public class AdvProperties extends Properties { + private static int SPLIT_LEN = 32; + + public AdvProperties() { + super(); + } + + public AdvProperties(Properties defaults) { + super(defaults); + } + + /** + * Create Properties from a String (compatible to this.toString) + * @param s the String + */ + public AdvProperties(String s) { + this(s.getBytes()); + } + + /** + * Create Properties from a byte array + * @param b the array + */ + public AdvProperties(byte[] b) { + ByteArrayInputStream in = new ByteArrayInputStream(b); + try { + load(in); + } catch (IOException ex) {} + } + + /** + * Return a value as int + * @param key the key + * @param def the default value + * @return the int + */ + public int getPropertyInt(String key, int def) { + String s = getProperty(key); + if (s==null) return def; + + try { + return Integer.parseInt(s); + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Set a byte array value. + * @param key the key + * @param bs the byte array + */ + public void setPropertyBytes(String key, byte[] bs) { + String val = new String(Base64.encodeBase64(bs, true)); + StringTokenizer st = new StringTokenizer(val, "\n"); + + int row=0; + while (st.hasMoreTokens()) { + String line = st.nextToken(); + assert line.indexOf('\r')==line.length()-1; + line = line.substring(0, line.length()-1); // remove the '\r' + setProperty(key+"."+Integer.toString(row, 36), line); + row++; + } + } + + /** + * Return a value as byte array. + * @param key the key + * @param def the default value + * @return the byte array + */ + public byte[] getPropertyBytes(String key, byte[] def) { + StringBuffer val = new StringBuffer(); + + int row=0; + String line; + do { + line = getProperty(key+"."+Integer.toString(row, 36), null); + + if (line==null && row==0) return def; + + if (line!=null) { + val.append(line); + //val.append("\n"); + } + row++; + } while(line!=null); + + return Base64.decodeBase64(val.toString().getBytes()); + } + + /** + * A new version of keys which sorts the keys. + * @return sortet keys + */ + @Override + public synchronized Enumeration keys() { + Enumeration keysEnum = super.keys(); + Vector keyList = new Vector(); + while(keysEnum.hasMoreElements()){ + keyList.add(keysEnum.nextElement()); + } + Collections.sort(keyList); + return keyList.elements(); + } + + + @Override + public String toString() { + return toString(null, false, false); + } + + /** + * Return the properties as String. + * @param comment a comment added to the String + * @param removeDate remove the date? + * @param hr add horizontal roulers? + * @return the String + */ + public String toString(String comment, boolean removeDate, boolean hr) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + String result; + + try { + store(out, comment); + } catch (IOException ex) {} + + result = out.toString(); + + if (removeDate) { + result = result.substring(result.indexOf('\n')+1); + } + + if (hr) { + result = "#==============================\n" + + result + + "#==============================\n"; + } + + return result; + } + + /** + * Filter the keys. + * @param prefix the prefix of the filtered keys + * @param exclude exclude the matching keys? (else include) + * @return new filtered properties + */ + public AdvProperties filter(String prefix, boolean exclude) { + AdvProperties result = new AdvProperties(); + + for(Object o : keySet()) { + boolean hit = o.toString().startsWith(prefix); + + if (exclude) hit = !hit; + + if (hit) { + result.put(o, get(o)); + } + } + return result; + } + + /** + * Return properties as byte array. + * @return the byte array. + */ + public byte[] asBytes () { + try { + String s = toString(null, true, false); + s = s.replaceAll("\r", ""); + return s.getBytes("ISO-8859-1"); + } catch (UnsupportedEncodingException ex) { + assert false; + return null; + } + } + + /** + * Sign this properties with the given key. + * @param keyName name of the key + * @param privateKey the key used for the signature + */ + public void sign(String keyName, PrivateKey privateKey) { + try { + byte[] data = asBytes(); + Signature signature = CryptoUtils.getSignature(); + signature.initSign(privateKey, CryptoUtils.getSecureRandom()); + signature.update(data); + setPropertyBytes(keyName, signature.sign()); + } catch (Throwable ex) { + Logger.getLogger("").log(Level.SEVERE, null, ex); + assert false; + } + } + + /** + * Verify a signature. + * @param keyName name if the signature key. + * @param publicKey the public key of the signature + * @return signature correct? + */ + public boolean verify(String keyName, PublicKey publicKey) { + try { + byte[] data = filter(keyName, true).asBytes(); + Signature signature = CryptoUtils.getSignature(); + signature.initVerify(publicKey); + signature.update(data); + return signature.verify(getPropertyBytes(keyName, null)); + } catch (Throwable ex) { + Logger.getLogger("").log(Level.SEVERE, null, ex); + return false; + } + } +} diff --git a/src/org/p2pvpn/tools/CryptoUtils.java b/src/org/p2pvpn/tools/CryptoUtils.java new file mode 100644 index 0000000..970d28e --- /dev/null +++ b/src/org/p2pvpn/tools/CryptoUtils.java @@ -0,0 +1,197 @@ +/* + Copyright 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.tools; + +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +/** + * Utility class to create differenty cryptographic algorithms. + * @author wolfgang + */ +public class CryptoUtils { + + private static final int RSA_KEYSIZE = 1024; + + static { + initBC(); + } + + /** + * Initialize the bouncy castle provider. + */ + static private void initBC() { + Security.addProvider(new BouncyCastleProvider()); + } + + /** + * @return a SecureRandom object + */ + static public SecureRandom getSecureRandom() { + try { + return SecureRandom.getInstance("SHA1PRNG"); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * @return a Signature object + */ + static public Signature getSignature() { + try { + return Signature.getInstance("SHA1withRSA", "BC"); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * @return a new KeyPair usable to sign things + */ + static public KeyPair createSignatureKeyPair() { + try { + KeyPairGenerator g = KeyPairGenerator.getInstance("RSA", "BC"); + g.initialize(RSA_KEYSIZE, getSecureRandom()); + return g.generateKeyPair(); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * @return a asymmetric Cipher + */ + static public Cipher getAsymmetricCipher() { + try { + return Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC"); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * @return a KeyPair that cna be used or an asymmetric cipher + */ + static public KeyPair createEncryptionKeyPair() { + return createSignatureKeyPair(); // also uses RSA + } + + /** + * Convert a byte array to a RSA public key + * @param ekey the byte array + * @return the public key + */ + static public PublicKey decodeRSAPublicKey(byte[] ekey) { + try { + X509EncodedKeySpec spec = new X509EncodedKeySpec(ekey); + KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); + return (RSAPublicKey) factory.generatePublic(spec); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * Convert a byte array to a RSA private key + * @param ekey the byte array + * @return the private key + */ + static public PrivateKey decodeRSAPrivateKey(byte[] ekey) { + try { + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(ekey); + KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); + return (RSAPrivateKey) factory.generatePrivate(spec); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * @return a hash algorithm + */ + static public MessageDigest getMessageDigest() { + try { + return MessageDigest.getInstance("SHA1"); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * @return a symmetric cipher + */ + static public Cipher getSymmetricCipher() { + try { + return Cipher.getInstance("AES/CBC/ISO10126Padding", "BC"); + } catch (Throwable t) { + Logger.getLogger("").log(Level.SEVERE, null, t); + assert false; + return null; + } + } + + /** + * @return the key length of the symmetric cipher in bytes + */ + static public int getSymmetricKeyLength() { + return 16; + } + + /** + * Create a symmetric key from bytes. + * @param b the bytes + * @return the symmetric key + */ + static public SecretKey decodeSymmetricKey(byte[] b) { + return new SecretKeySpec(b, 0, 16, "AES"); + } +} diff --git a/src/org/p2pvpn/tools/ProfileManager.java b/src/org/p2pvpn/tools/ProfileManager.java new file mode 100644 index 0000000..0b981dd --- /dev/null +++ b/src/org/p2pvpn/tools/ProfileManager.java @@ -0,0 +1,181 @@ +package org.p2pvpn.tools; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author steve.kliebisch + */ +public class ProfileManager { + + private static Properties props = new Properties(); + private static final String file = "profile.ini"; + private static String networkName = "default"; + + + static final File profileFile = new File(file); + + /* + static{ + props = new Properties();//Create the properties object + //create new File if not exist + if(!profileFile.exists()) + { + try { + setDefaults(networkName); + write(profileFile); + } catch (IOException ex) { + Logger.getLogger(ProfileManager.class.getName()).log(Level.SEVERE, null, ex); + } + } + } +*/ + public ProfileManager load(String network){ + networkName = network; + + //load values + try { + read(profileFile); //Read the ini file + } catch (IOException ex) { + Logger.getLogger(ProfileManager.class.getName()).log(Level.SEVERE, null, ex); + } + return this; + } + + public void flush(){ + try { + write(profileFile); + } catch (IOException ex) { + Logger.getLogger(ProfileManager.class.getName()).log(Level.SEVERE, null, ex); + } + + } + + public void putGlobal(String key, String val){ + props.setProperty(key, val); + } + + public void put(String key, String val){ + props.setProperty(networkName+'.'+key, val); + } + + public void putInt(String key, Integer val){ + props.setProperty(networkName+'.'+key, val.toString() ); + } + + public void putBoolean(String key, Boolean val){ + props.setProperty(networkName+'.'+key, val.toString() ); + } + + public void putDouble(String key, Double val){ + props.setProperty(networkName+'.'+key, val.toString() ); + } + + + public String getGlobal(String key, String def){ + return props.getProperty(key, def); + } + + public String get(String key, String def){ + return props.getProperty(networkName+'.'+key, def); + } + + public Integer getInt(String key, Integer def){ + return Integer.parseInt( props.getProperty(networkName+'.'+key, def.toString() ) ); + } + + public Boolean getBoolean(String key, Boolean def){ + return ( props.getProperty(networkName + '.' + key, def.toString() ).equals("true") ) ? true : false; + } + + public Double getDouble(String key, Integer def){ + Double d = 0.0; + try { + d = Double.valueOf( props.getProperty(networkName + '.' + key, def.toString() ) ); + } catch (NumberFormatException e) {} + return d; + } + + public void remove(String key) + { + props.remove(key); + } + + public ProfileDescription[] getProfiles() { + final List result = new ArrayList(); + + for (Entry entry : props.entrySet()) { + final String key = entry.getKey().toString(); + final String value = entry.getValue().toString(); + + if (key.endsWith(".name")) { + result.add(new ProfileDescription( + key.substring(0, key.length()-5), + value)); + } + } + + ProfileDescription[] resultArray = new ProfileDescription[result.size()]; + result.toArray(resultArray); + + Arrays.sort(resultArray, new Comparator() { + public int compare(ProfileDescription p1, ProfileDescription p2) { + return p1.getName().compareTo(p2.getName()); + } + }); + + return resultArray; + } + + public static void setDefaults(String defaultName){ + props.setProperty(defaultName+'.'+"name", "no name"); + props.setProperty(defaultName+'.'+"serverPort", "0"); + props.setProperty(defaultName+'.'+"popupChat", "1"); + props.setProperty(defaultName+'.'+"sendLimit", "0.0"); + props.setProperty(defaultName+'.'+"recLimit", "0.0"); + props.setProperty(defaultName+'.'+"sendBufferSize", "10"); + props.setProperty(defaultName+'.'+"tcpFlush", "0"); + } + + + private static void read(File file) throws IOException { + FileInputStream fis = new FileInputStream(file);//Create a FileInputStream + props.load(fis);//load the ini to the Properties file + fis.close();//close + } + + private static void write(File file) throws IOException { + FileOutputStream fos = new FileOutputStream(file);//Create a FileOutputStream + props.store(fos, "");//write the Properties object values to our ini file + fos.close();//close + } + + public class ProfileDescription { + private final String key; + private final String name; + + public ProfileDescription(String key, String name) { + this.key = key; + this.name = name; + } + + public String getKey() { + return key; + } + + public String getName() { + return name; + } + } +} diff --git a/src/org/p2pvpn/tools/SocketAddrStr.java b/src/org/p2pvpn/tools/SocketAddrStr.java new file mode 100644 index 0000000..6034c5c --- /dev/null +++ b/src/org/p2pvpn/tools/SocketAddrStr.java @@ -0,0 +1,61 @@ +/* + Copyright 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.tools; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SocketAddrStr { + public static final Pattern ipv4 = Pattern.compile("\\s*([^:]+):(\\d+)\\s*"); + public static final Pattern ipv6 = Pattern.compile("\\s*\\[([^\\]]+)\\]:(\\d+)\\s*"); + + public static String socketAddrToStr(InetSocketAddress sAddr) { + InetAddress a = sAddr.getAddress(); + if (a instanceof Inet4Address) { + return a.getHostAddress()+":"+sAddr.getPort(); + } else if (a instanceof Inet6Address) { + return "["+a.getHostAddress()+"]:"+sAddr.getPort(); + } else return sAddr.toString(); + } + + public static InetSocketAddress parseSocketAddr(String s) throws Exception { + String host=null, port=null; + s = s.trim(); + Matcher m4 = ipv4.matcher(s); + Matcher m6 = ipv6.matcher(s); + if (m4.matches()) { + host = m4.group(1); + port = m4.group(2); + } else if (m6.matches()) { + host = m6.group(1); + port = m6.group(2); + } + + if (host!=null && port!=null) { + return new InetSocketAddress(host, Integer.parseInt(port)); + } + + throw new Exception("'"+s+"' is not a valid socket address"); + } +} diff --git a/src/org/p2pvpn/tools/VersionizedMap.java b/src/org/p2pvpn/tools/VersionizedMap.java new file mode 100644 index 0000000..d827855 --- /dev/null +++ b/src/org/p2pvpn/tools/VersionizedMap.java @@ -0,0 +1,103 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.tools; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * This is a Map with the version. The version is increased with every change made. + * @author Wolfgang Ginolas + */ +public class VersionizedMap implements Map, Serializable { + + private Map map; + + private long version; + + public VersionizedMap(Map map) { + this.map = map; + version = 0; + } + + public VersionizedMap() { + this(new HashMap()); + } + + public long getVersion() { + return version; + } + + public int size() { + return map.size(); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + public boolean containsValue(Object val) { + return map.containsValue(val); + } + + public V get(Object key) { + return map.get(key); + } + + public V put(K key, V val) { + version++; + return map.put(key, val); + } + + public V remove(Object key) { + version++; + return map.remove(key); + } + + public void putAll(Map m) { + version++; + map.putAll(m); + } + + public void clear() { + version++; + map.clear(); + } + + public Set keySet() { + return map.keySet(); + } + + public Collection values() { + return map.values(); + } + + public Set> entrySet() { + return map.entrySet(); + } + +} diff --git a/src/org/p2pvpn/tuntap/TunTap.java b/src/org/p2pvpn/tuntap/TunTap.java new file mode 100644 index 0000000..9b56b8f --- /dev/null +++ b/src/org/p2pvpn/tuntap/TunTap.java @@ -0,0 +1,131 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.tuntap; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * An apstract claas for an virtual network adapter. A different implementation + * for every operating system is needed. + * @author Wolfgang Ginolas + */ +public abstract class TunTap { + + private byte[] ip = null; + + /** + * Load a libary (*.so or *.dll). + * @param libs the libary names + * @throws java.io.IOException + */ + static void loadLib(String... libs) throws Throwable { + Throwable e=null; + for(String lib : libs) { + try { + System.load(new File(lib).getCanonicalPath()); + break; + } catch (Throwable eio) {e = eio;} + } + if (e!=null) throw e; + } + + /*static void loadLibFromRecsource(String lib, String suffix) throws IOException { + File tmp = File.createTempFile("lib", suffix); + tmp.deleteOnExit(); + InputStream in = TunTap.class.getClassLoader().getResourceAsStream(lib); + OutputStream out = new FileOutputStream(tmp); + + byte[] buffer = new byte[1024*8]; + int len; + + while (0<(len = in.read(buffer))) { + out.write(buffer, 0, len); + } + in.close(); + out.close(); + + System.load(tmp.getCanonicalPath()); + }*/ + + /** + * Return a TunTap object for the currently used operating system. + * @return the TunTap object + * @throws java.lang.Exception + */ + static public TunTap createTunTap() throws Exception { + String osName = System.getProperty("os.name"); + + if (osName.startsWith("Windows")) { + return new TunTapWindows(); + } else if (osName.equals("Linux")) { + return new TunTapLinux(); + } else { + throw new Exception("The operating system "+osName+" is not supported!"); + } + } + + /** + * @return the name of the virtuel network device + */ + abstract public String getDev(); + + /** + * Close the device. + */ + abstract public void close(); + + /** + * Send a packet to the virtual network adapter. + * @param b the packet + * @param len the length of the packet + */ + abstract public void write(byte[] b, int len); + + /** + * Read a packet from the virtual network adapter. + * @param b the packet + * @return length if the packet + */ + abstract public int read(byte[] b); + + /** + * Set the IP address of the virtual network adapter. + * @param ip the IP + * @param subnetmask the subnet mask + */ + public void setIP(String ip, String subnetmask) { + try { + this.ip = InetAddress.getByName(ip).getAddress(); + } catch (UnknownHostException ex) { + } + } + + /** + * Return the last set IP address. + * @return the ip address + */ + public byte[] getIPBytes() { + return ip; + } + +} diff --git a/src/org/p2pvpn/tuntap/TunTapLinux.java b/src/org/p2pvpn/tuntap/TunTapLinux.java new file mode 100644 index 0000000..d8163e2 --- /dev/null +++ b/src/org/p2pvpn/tuntap/TunTapLinux.java @@ -0,0 +1,73 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.tuntap; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * The TunTap class for linux. + * @author Wolfgang Ginolas + */ +public class TunTapLinux extends TunTap { + static { + try { + loadLib("clib/libTunTapLinux.so", "clib/libTunTapLinux64.so", "clib/libTunTapLinuxMips.so"); + } catch (Throwable e) { + Logger.getLogger("").log(Level.SEVERE, "Could not load libTunTapLinux.so", e); + } + } + + private int fd; + private String dev; + + /** + * Create a new TunTapLinux + * @throws java.lang.Exception + */ + public TunTapLinux() throws Exception { + if (1==openTun()) throw new Exception("Could not open '/dev/net/tun!'\n" + + "Please run this application as root."); + } + + public String getDev() { + return dev; + } + + private native int openTun(); + + public native void close(); + + public native void write(byte[] b, int len); + + public native int read(byte[] b); + + public void setIP(String ip, String subnetmask) { + super.setIP(ip, subnetmask); + try { + Process p = Runtime.getRuntime().exec("ifconfig "+dev+" "+ip+" netmask "+subnetmask); + Logger.getLogger("").log(Level.INFO, "IP set successfully ("+p.waitFor()+")"); + } catch (Exception e) { + Logger.getLogger("").log(Level.WARNING, "Could not set IP!", e); + } + } + +} diff --git a/src/org/p2pvpn/tuntap/TunTapWindows.java b/src/org/p2pvpn/tuntap/TunTapWindows.java new file mode 100644 index 0000000..8381744 --- /dev/null +++ b/src/org/p2pvpn/tuntap/TunTapWindows.java @@ -0,0 +1,110 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package org.p2pvpn.tuntap; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.p2pvpn.tools.AdapterManager; + +/** + * The TunTap class for Windows + * @author Wolfgang Ginolas + */ +public class TunTapWindows extends TunTap { + static { + try { + loadLib("clib\\libTunTapWindows.dll", "clib\\libTunTapWindows64.dll"); + } catch (Throwable e) { + Logger.getLogger("").log(Level.SEVERE, "Could not load libTunTapWindows.dll", e); + } + } + + private long cPtr; + private String dev; + + /** + * Create a new TunTapWindows. + * @throws java.lang.Exception + */ + public TunTapWindows() throws Exception { + + /* try to install Win Tap Driver + Integer erg = openTun(); + if(erg == 1){ + checkAndInstallAdapter(); + if (1==openTun())throw new Exception("ERROR during Install. Try as administrator."); + } else if (erg == 2){ + throw new Exception("Could not open Virtual Ethernet Adapter!\n" + + "Make sure the TAP-Win32 driver ist installed."); // TODO More error messages + } + */ + + + if (0!=openTun()) throw new Exception("Could not open Virtual Eternat Adapter!\n" + + "Make sure the TAP-Win32 driver ist installed."); // TODO More error messages + } + + public String getDev() { + return dev; + } + + private native int openTun(); + + public native void close(); + + public native void write(byte[] b, int len); + + public native int read(byte[] b); + + public void setIP(String ip, String subnetmask) { + super.setIP(ip, subnetmask); + try { + String[] cmd = { + "netsh", "interface", "ip", "set", "address", dev, "static", ip, subnetmask + }; + String[] metric = { + "netsh", "interface", "ip", "set", "interface", "interface="+dev, + "metric=10" + }; + + String[] rename = { + "netsh", "interface", "set", "interface", "name="+dev, + "newname=P2P VPN" + }; + + Process p = Runtime.getRuntime().exec(cmd); + p = Runtime.getRuntime().exec(metric); + p = Runtime.getRuntime().exec(rename); + //System.out.println("IP set successfully ("+p.waitFor()+")"); + // netsh takes a long time... don't wait for it + } catch (Exception e) { + Logger.getLogger("").log(Level.WARNING, "Could not set IP!", e); + } + } + + public Boolean checkAndInstallAdapter() { + AdapterManager adapter = new AdapterManager(); + if(adapter.install()) + return true; + + return false; + } +} diff --git a/src/test/org/p2pvpn/tools/TestAdvProperties.java b/src/test/org/p2pvpn/tools/TestAdvProperties.java new file mode 100644 index 0000000..e793f71 --- /dev/null +++ b/src/test/org/p2pvpn/tools/TestAdvProperties.java @@ -0,0 +1,62 @@ +/* + Copyright 2008, 2009 Wolfgang Ginolas + + This file is part of P2PVPN. + + P2PVPN is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Foobar is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Foobar. If not, see . +*/ + +package test.org.p2pvpn.tools; + +import java.security.KeyPair; +import java.security.PublicKey; +import org.junit.Before; +import org.junit.Test; +import org.p2pvpn.tools.AdvProperties; +import org.p2pvpn.tools.CryptoUtils; +import static org.junit.Assert.*; + +public class TestAdvProperties { + AdvProperties p; + + @Before public void before() { + p = new AdvProperties(); + + p.setProperty("a", "1"); + p.setProperty("b", "2"); + p.setProperty("c", "3"); + } + + @Test public void testStore() { + assertEquals("a=1\nb=2\nc=3\n", p.toString(null, true, false)); + } + + @Test public void testSign() { + KeyPair kp = CryptoUtils.createSignatureKeyPair(); + KeyPair kp2 = CryptoUtils.createSignatureKeyPair(); + p.sign("signature", kp.getPrivate()); + assertTrue(p.verify("signature", kp.getPublic())); + assertFalse(p.verify("signature", kp2.getPublic())); + } + + @Test public void testDecodeKey() { + KeyPair kp = CryptoUtils.createSignatureKeyPair(); + p.setPropertyBytes("publicKey", kp.getPublic().getEncoded()); + p.sign("signature", kp.getPrivate()); + + PublicKey key = CryptoUtils.decodeRSAPublicKey(p.getPropertyBytes("publicKey", null)); + assertTrue(p.verify("signature", key)); + } + +}