/* This file is part of jpcsp. Jpcsp 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. Jpcsp 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 Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.network.proonline; import static jpcsp.HLE.modules.sceNet.convertMacAddressToString; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_ACCEPT; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_CANCEL; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_COMPLETE; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_DATA; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_DISCONNECT; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_HELLO; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_INTERNAL_PING; import static jpcsp.HLE.modules.sceNetAdhocMatching.PSP_ADHOC_MATCHING_EVENT_JOIN; import static jpcsp.hardware.Wlan.MAC_ADDRESS_LENGTH; import jpcsp.HLE.modules.sceNetAdhocMatching; import jpcsp.network.adhoc.MatchingObject; /** * @author gid15 * */ public class MatchingPacketFactory { public static final int ADHOC_MATCHING_PACKET_PING = 0; public static final int ADHOC_MATCHING_PACKET_HELLO = 1; public static final int ADHOC_MATCHING_PACKET_JOIN = 2; public static final int ADHOC_MATCHING_PACKET_ACCEPT = 3; public static final int ADHOC_MATCHING_PACKET_CANCEL = 4; public static final int ADHOC_MATCHING_PACKET_BULK = 5; public static final int ADHOC_MATCHING_PACKET_BULK_ABORT = 6; public static final int ADHOC_MATCHING_PACKET_BIRTH = 7; public static final int ADHOC_MATCHING_PACKET_DEATH = 8; public static final int ADHOC_MATCHING_PACKET_BYE = 9; private static abstract class MatchingPacketOpcode extends ProOnlineAdhocMatchingEventMessage { public MatchingPacketOpcode(MatchingObject matchingObject, int event, byte[] message, int length) { super(matchingObject, event, message, length); } public MatchingPacketOpcode(MatchingObject matchingObject, int event, int packetOpcode) { super(matchingObject, event, packetOpcode); } @Override public byte[] getMessage() { byte[] message = new byte[getMessageLength()]; offset = 0; addToBytes(message, (byte) getPacketOpcode()); return message; } @Override public void setMessage(byte[] message, int length) { if (length >= getMessageLength()) { offset = 0; setPacketOpcode(copyByteFromBytes(message)); } } @Override public int getMessageLength() { return 1; } } private static class MatchingPacketPing extends MatchingPacketOpcode { public MatchingPacketPing(MatchingObject matchingObject) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_INTERNAL_PING, ADHOC_MATCHING_PACKET_PING); } public MatchingPacketPing(MatchingObject matchingObject, byte[] message, int length) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_INTERNAL_PING, message, length); } } private static class MatchingPacketHello extends ProOnlineAdhocMatchingEventMessage { public MatchingPacketHello(MatchingObject matchingObject, int address, int length, byte[] toMacAddress) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_HELLO, ADHOC_MATCHING_PACKET_HELLO, address, length, toMacAddress); } public MatchingPacketHello(MatchingObject matchingObject) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_HELLO, ADHOC_MATCHING_PACKET_HELLO); } public MatchingPacketHello(MatchingObject matchingObject, byte[] message, int length) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_HELLO, message, length); } } private static class MatchingPacketJoin extends ProOnlineAdhocMatchingEventMessage { public MatchingPacketJoin(MatchingObject matchingObject, int address, int length, byte[] toMacAddress) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_JOIN, ADHOC_MATCHING_PACKET_JOIN, address, length, toMacAddress); } public MatchingPacketJoin(MatchingObject matchingObject) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_JOIN, ADHOC_MATCHING_PACKET_JOIN); } public MatchingPacketJoin(MatchingObject matchingObject, byte[] message, int length) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_JOIN, message, length); } } /** * @author gid15 * * A MatchingPacketAccept is consisting of: * - 1 byte for the event * - 4 bytes for the message data length * - 4 bytes for the sibling count * - n bytes for the message data * - m bytes for the sibling MAC addresses (6 bytes per sibling) */ private static class MatchingPacketAccept extends ProOnlineAdhocMatchingEventMessage { protected static final int HEADER_SIZE = 1 + 4 + 4; public MatchingPacketAccept(MatchingObject matchingObject, int address, int length, byte[] toMacAddress) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_ACCEPT, ADHOC_MATCHING_PACKET_ACCEPT, address, length, toMacAddress); } public MatchingPacketAccept(MatchingObject matchingObject) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_ACCEPT, ADHOC_MATCHING_PACKET_ACCEPT); } public MatchingPacketAccept(MatchingObject matchingObject, byte[] message, int length) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_ACCEPT, message, length); } @Override public byte[] getMessage() { byte[] message = new byte[getMessageLength()]; offset = 0; addToBytes(message, (byte) getPacketOpcode()); addInt32ToBytes(message, getDataLength()); int siblingCount = getSiblingCount(); addInt32ToBytes(message, siblingCount); addToBytes(message, data); for (int i = 0; i < siblingCount; i++) { byte[] macAddress = getMatchingObject().getMembers().get(i).macAddress; addToBytes(message, macAddress); if (log.isDebugEnabled()) { log.debug(String.format("Sending Sibling#%d: MAC %s", i, convertMacAddressToString(macAddress))); } } return message; } @Override public void setMessage(byte[] message, int length) { if (length >= HEADER_SIZE) { offset = 0; setPacketOpcode(copyByteFromBytes(message)); int dataLength = copyInt32FromBytes(message); int siblingCount = copyInt32FromBytes(message); int restLength = length - HEADER_SIZE - siblingCount * MAC_ADDRESS_LENGTH; data = new byte[Math.min(dataLength, restLength)]; copyFromBytes(message, data); byte[] mac = new byte[MAC_ADDRESS_LENGTH]; for (int i = 0; i < siblingCount; i++) { copyFromBytes(message, mac); if (log.isDebugEnabled()) { log.debug(String.format("Received Sibling#%d: MAC %s", i, convertMacAddressToString(mac))); } } } } protected int getSiblingCount() { // Send siblings only for MODE_HOST if (getMatchingObject().getMode() != sceNetAdhocMatching.PSP_ADHOC_MATCHING_MODE_HOST) { return 0; } return getMatchingObject().getMembers().size(); } @Override public int getMessageLength() { return HEADER_SIZE + getDataLength() + getSiblingCount() * MAC_ADDRESS_LENGTH; } @Override public void processOnReceive(int macAddr, int optData, int optLen) { // Send the PSP_ADHOC_MATCHING_EVENT_ACCEPT event immediately followed by // PSP_ADHOC_MATCHING_EVENT_COMPLETE super.processOnReceive(macAddr, optData, optLen); getMatchingObject().notifyCallbackEvent(PSP_ADHOC_MATCHING_EVENT_COMPLETE, macAddr, optLen, optData); } @Override public void processOnSend(int macAddr, int optData, int optLen) { super.processOnSend(macAddr, optData, optLen); // Send the PSP_ADHOC_MATCHING_EVENT_COMPLETE event from the matching input thread getMatchingObject().addCallbackEvent(PSP_ADHOC_MATCHING_EVENT_COMPLETE, macAddr, 0, 0); } } private static class MatchingPacketCancel extends ProOnlineAdhocMatchingEventMessage { public MatchingPacketCancel(MatchingObject matchingObject, int address, int length, byte[] toMacAddress) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_CANCEL, ADHOC_MATCHING_PACKET_CANCEL, address, length, toMacAddress); } public MatchingPacketCancel(MatchingObject matchingObject) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_CANCEL, ADHOC_MATCHING_PACKET_CANCEL); } public MatchingPacketCancel(MatchingObject matchingObject, byte[] message, int length) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_CANCEL, message, length); } } private static class MatchingPacketBulk extends ProOnlineAdhocMatchingEventMessage { public MatchingPacketBulk(MatchingObject matchingObject, int address, int length, byte[] toMacAddress) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_DATA, ADHOC_MATCHING_PACKET_BULK, address, length, toMacAddress); } public MatchingPacketBulk(MatchingObject matchingObject) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_DATA, ADHOC_MATCHING_PACKET_BULK); } public MatchingPacketBulk(MatchingObject matchingObject, byte[] message, int length) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_DATA, message, length); } } private static class MatchingPacketBye extends MatchingPacketOpcode { public MatchingPacketBye(MatchingObject matchingObject) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_DISCONNECT, ADHOC_MATCHING_PACKET_BYE); } public MatchingPacketBye(MatchingObject matchingObject, byte[] message, int length) { super(matchingObject, PSP_ADHOC_MATCHING_EVENT_DISCONNECT, message, length); } } public static ProOnlineAdhocMatchingEventMessage createPacket(ProOnlineNetworkAdapter proOnline, MatchingObject matchingObject, byte[] message, int length) { if (length > 0 && message != null && message.length > 0) { switch (message[0]) { case ADHOC_MATCHING_PACKET_PING: return new MatchingPacketPing(matchingObject, message, length); case ADHOC_MATCHING_PACKET_HELLO: return new MatchingPacketHello(matchingObject, message, length); case ADHOC_MATCHING_PACKET_JOIN: return new MatchingPacketJoin(matchingObject, message, length); case ADHOC_MATCHING_PACKET_ACCEPT: return new MatchingPacketAccept(matchingObject, message, length); case ADHOC_MATCHING_PACKET_CANCEL: return new MatchingPacketCancel(matchingObject, message, length); case ADHOC_MATCHING_PACKET_BULK: return new MatchingPacketBulk(matchingObject, message, length); case ADHOC_MATCHING_PACKET_BYE: return new MatchingPacketBye(matchingObject, message, length); } } return null; } public static ProOnlineAdhocMatchingEventMessage createPacket(ProOnlineNetworkAdapter proOnline, MatchingObject matchingObject, int event) { switch (event) { case PSP_ADHOC_MATCHING_EVENT_INTERNAL_PING: return new MatchingPacketPing(matchingObject); case PSP_ADHOC_MATCHING_EVENT_HELLO: return new MatchingPacketHello(matchingObject); case PSP_ADHOC_MATCHING_EVENT_JOIN: return new MatchingPacketJoin(matchingObject); case PSP_ADHOC_MATCHING_EVENT_ACCEPT: return new MatchingPacketAccept(matchingObject); case PSP_ADHOC_MATCHING_EVENT_CANCEL: return new MatchingPacketCancel(matchingObject); case PSP_ADHOC_MATCHING_EVENT_DATA: return new MatchingPacketBulk(matchingObject); case PSP_ADHOC_MATCHING_EVENT_DISCONNECT: return new MatchingPacketBye(matchingObject); } return null; } public static ProOnlineAdhocMatchingEventMessage createPacket(ProOnlineNetworkAdapter proOnline, MatchingObject matchingObject, int event, int data, int dataLength, byte[] macAddress) { switch (event) { case PSP_ADHOC_MATCHING_EVENT_INTERNAL_PING: return new MatchingPacketPing(matchingObject); case PSP_ADHOC_MATCHING_EVENT_HELLO: return new MatchingPacketHello(matchingObject, data, dataLength, macAddress); case PSP_ADHOC_MATCHING_EVENT_JOIN: return new MatchingPacketJoin(matchingObject, data, dataLength, macAddress); case PSP_ADHOC_MATCHING_EVENT_ACCEPT: return new MatchingPacketAccept(matchingObject, data, dataLength, macAddress); case PSP_ADHOC_MATCHING_EVENT_CANCEL: return new MatchingPacketCancel(matchingObject, data, dataLength, macAddress); case PSP_ADHOC_MATCHING_EVENT_DATA: return new MatchingPacketBulk(matchingObject, data, dataLength, macAddress); case PSP_ADHOC_MATCHING_EVENT_DISCONNECT: return new MatchingPacketBye(matchingObject); } return null; } }