/* Copyright (C) 2011 monte This file is part of PSP NetParty. PSP NetParty is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package pspnetparty.client.swt; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.dialogs.IDialogConstants; import pspnetparty.lib.Utility; import pspnetparty.lib.socket.IProtocol; import pspnetparty.lib.socket.IProtocolDriver; import pspnetparty.lib.socket.ISocketConnection; import pspnetparty.lib.socket.PacketData; import pspnetparty.lib.socket.TransportLayer; import pspnetparty.wlan.WlanDevice; import pspnetparty.wlan.WlanLibrary; import pspnetparty.wlan.WlanNetwork; public class WlanProxyLibrary implements WlanLibrary { public static final String LIBRARY_NAME = "Proxy"; private PlayClient application; private boolean isSSIDEnabled; private ProxyProtocol protocol = new ProxyProtocol(); private ISocketConnection activeConnection = ISocketConnection.NULL; private String ssid; private ArrayList<WlanNetwork> networks = new ArrayList<WlanNetwork>(); private final Object captureLock = new Object(); private ByteBuffer captureBuffer = ByteBuffer.allocate(1); private ByteBuffer sendBuffer = ByteBuffer.allocate(1); public WlanProxyLibrary(PlayClient application) { this.application = application; } @Override public boolean isReady() { return true; } @Override public String getName() { return LIBRARY_NAME; } @Override public void findDevices(List<WlanDevice> devices) { devices.add(new ProxyWlanDevice()); } @Override public boolean isSSIDEnabled() { return isSSIDEnabled; } private class ProxyWlanDevice implements WlanDevice { private TransportLayer transport; private InetSocketAddress address; public ProxyWlanDevice() { } @Override public String getName() { return "Proxyに接続"; } @Override public byte[] getHardwareAddress() { return null; } @Override public void open() throws IOException { ConnectAddressDialog dialog = new ConnectAddressDialog(application.getRoomWindow().getShell()); switch (dialog.open()) { case IDialogConstants.OK_ID: try { address = new InetSocketAddress(dialog.getHostName(), dialog.getPort()); transport = dialog.getTransport(); } catch (Exception e) { throw new IOException(e); } break; case IDialogConstants.CANCEL_ID: throw new IOException(); } isSSIDEnabled = false; switch (transport) { case TCP: application.connectTcp(address, protocol); break; case UDP: application.connectUdp(address, protocol); break; } try { Thread.sleep(100); } catch (InterruptedException e) { throw new IOException(e); } } @Override public int capturePacket(ByteBuffer buffer) { synchronized (captureLock) { int remaining = captureBuffer.remaining(); if (remaining > 0) { // System.out.println("Capture2: " + captureBuffer); // System.out.println("Capture3: " + buffer); buffer.put(captureBuffer); return remaining; } } try { Thread.sleep(10); } catch (InterruptedException e) { } return 0; } @Override public boolean sendPacket(ByteBuffer buffer) { if (sendBuffer.capacity() <= buffer.capacity()) { sendBuffer = ByteBuffer.allocateDirect(buffer.capacity() * 2); } else { sendBuffer.clear(); } sendBuffer.put(WlanProxyConstants.BYTE_COMMAND_PACKET); sendBuffer.put(buffer); sendBuffer.flip(); activeConnection.send(sendBuffer); return true; } @Override public String getSSID() { return ssid; } @Override public void setSSID(String ssid) { WlanProxyLibrary.this.ssid = ssid; activeConnection.send(Utility.encode(WlanProxyConstants.COMMAND_SET_SSID + ssid)); } @Override public boolean scanNetwork() { activeConnection.send(Utility.encode(String.valueOf(WlanProxyConstants.COMMAND_SCAN_NETWORK))); return true; } @Override public boolean findNetworks(List<WlanNetwork> networkList) { activeConnection.send(Utility.encode(String.valueOf(WlanProxyConstants.COMMAND_FIND_NETWORK))); networkList.addAll(networks); return true; } @Override public void close() { activeConnection.disconnect(); activeConnection = ISocketConnection.NULL; } } private class ProxyProtocol implements IProtocol { @Override public void log(String message) { application.getArenaWindow().appendToSystemLog(message, true); } @Override public String getProtocol() { return WlanProxyConstants.PROTOCOL; } @Override public IProtocolDriver createDriver(ISocketConnection connection) { application.getArenaWindow().appendToSystemLog("プロキシに接続しました: " + connection.getRemoteAddress(), true); activeConnection = connection; ProxyProtocolDriver driver = new ProxyProtocolDriver(); driver.connection = connection; return driver; } } private class ProxyProtocolDriver implements IProtocolDriver { private ISocketConnection connection; @Override public ISocketConnection getConnection() { return connection; } @Override public boolean process(PacketData data) { ByteBuffer buffer = data.getBuffer(); application.getArenaWindow().appendToSystemLog(buffer.toString(), true); int origLimit = buffer.limit(); buffer.limit(1); char c = Utility.decode(buffer).charAt(0); buffer.limit(origLimit); switch (c) { case WlanProxyConstants.COMMAND_PACKET: synchronized (captureLock) { if (captureBuffer.capacity() <= buffer.capacity()) { captureBuffer = ByteBuffer.allocateDirect(buffer.capacity() * 2); } else { captureBuffer.clear(); } // System.out.println("Capture1: " + buffer); captureBuffer.put(buffer); captureBuffer.flip(); } break; case WlanProxyConstants.COMMAND_GET_SSID: { String ssid = Utility.decode(buffer); WlanProxyLibrary.this.ssid = ssid; break; } case WlanProxyConstants.COMMAND_FIND_NETWORK: { networks.clear(); String message = Utility.decode(buffer); // application.getLogWindow().appendLog(message, true, false); for (String row : message.split("\f")) { String[] values = row.split("\t"); if (values.length != 2) continue; try { String ssid = values[0]; int rssi = Integer.parseInt(values[1]); WlanNetwork network = new WlanNetwork(ssid, rssi); networks.add(network); } catch (NumberFormatException e) { } } break; } case WlanProxyConstants.COMMAND_SSID_FEATURE_ENABLED: isSSIDEnabled = true; break; case WlanProxyConstants.COMMAND_SSID_FEATURE_DISABLED: isSSIDEnabled = false; break; default: return false; } return true; } @Override public void connectionDisconnected() { application.getArenaWindow().appendToSystemLog("プロキシと切断しました: " + connection.getRemoteAddress(), true); } @Override public void errorProtocolNumber(String number) { } } }