PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/src/jpcsp/network/adhoc/PtpObject.java

http://jpcsp.googlecode.com/
Java | 429 lines | 327 code | 61 blank | 41 comment | 42 complexity | 630b7a1dda42756ed73463fa778f7184 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. This file is part of jpcsp.
  3. Jpcsp is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. Jpcsp is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. package jpcsp.network.adhoc;
  15. import java.io.IOException;
  16. import java.net.BindException;
  17. import java.net.InetAddress;
  18. import java.net.SocketAddress;
  19. import java.net.SocketException;
  20. import java.net.SocketTimeoutException;
  21. import java.net.UnknownHostException;
  22. import jpcsp.Memory;
  23. import jpcsp.HLE.Modules;
  24. import jpcsp.HLE.TPointer;
  25. import jpcsp.HLE.TPointer32;
  26. import jpcsp.HLE.kernel.types.SceKernelErrors;
  27. import jpcsp.HLE.kernel.types.SceKernelThreadInfo;
  28. import jpcsp.HLE.kernel.types.pspNetMacAddress;
  29. import jpcsp.network.INetworkAdapter;
  30. import jpcsp.util.Utilities;
  31. /**
  32. * @author gid15
  33. *
  34. */
  35. public abstract class PtpObject extends PdpObject {
  36. /** Destination MAC address */
  37. private pspNetMacAddress destMacAddress;
  38. /** Destination port */
  39. private int destPort;
  40. /** Retry delay */
  41. private int retryDelay;
  42. /** Retry count */
  43. private int retryCount;
  44. /** Queue size */
  45. private int queue;
  46. /** Bytes sent */
  47. private int sentData;
  48. // Polling period (micro seconds) for blocking operations
  49. protected static final int BLOCKED_OPERATION_POLLING_MICROS = 10000;
  50. private AdhocMessage receivedMessage;
  51. private int receivedMessageOffset;
  52. protected static abstract class BlockedPtpAction extends BlockedPdpAction {
  53. protected final PtpObject ptpObject;
  54. protected BlockedPtpAction(PtpObject ptpObject, int timeout) {
  55. super(ptpObject, timeout);
  56. this.ptpObject = ptpObject;
  57. }
  58. }
  59. protected static class BlockedPtpAccept extends BlockedPtpAction {
  60. private final int peerMacAddr;
  61. private final int peerPortAddr;
  62. public BlockedPtpAccept(PtpObject ptpObject, int peerMacAddr, int peerPortAddr, int timeout) {
  63. super(ptpObject, timeout);
  64. this.peerMacAddr = peerMacAddr;
  65. this.peerPortAddr = peerPortAddr;
  66. }
  67. @Override
  68. protected boolean poll() throws IOException {
  69. return ptpObject.pollAccept(peerMacAddr, peerPortAddr, thread);
  70. }
  71. @Override
  72. protected int getExceptionResult(IOException e) {
  73. return SceKernelErrors.ERROR_NET_ADHOC_TIMEOUT;
  74. }
  75. }
  76. protected static class BlockedPtpConnect extends BlockedPtpAction {
  77. public BlockedPtpConnect(PtpObject ptpObject, int timeout) {
  78. super(ptpObject, timeout);
  79. }
  80. @Override
  81. protected boolean poll() throws IOException {
  82. return ptpObject.pollConnect(thread);
  83. }
  84. @Override
  85. protected int getExceptionResult(IOException e) {
  86. return SceKernelErrors.ERROR_NET_ADHOC_CONNECTION_REFUSED;
  87. }
  88. }
  89. protected static class BlockedPtpRecv extends BlockedPtpAction {
  90. final protected TPointer data;
  91. final protected TPointer32 dataLengthAddr;
  92. protected BlockedPtpRecv(PtpObject ptpObject, TPointer data, TPointer32 dataLengthAddr, int timeout) {
  93. super(ptpObject, timeout);
  94. this.data = data;
  95. this.dataLengthAddr = dataLengthAddr;
  96. }
  97. @Override
  98. protected boolean poll() throws IOException {
  99. return ptpObject.pollRecv(data, dataLengthAddr, thread);
  100. }
  101. @Override
  102. protected int getExceptionResult(IOException e) {
  103. return SceKernelErrors.ERROR_NET_ADHOC_TIMEOUT;
  104. }
  105. }
  106. public PtpObject(PtpObject ptpObject) {
  107. super(ptpObject);
  108. destMacAddress = ptpObject.destMacAddress;
  109. destPort = ptpObject.destPort;
  110. retryDelay = ptpObject.retryDelay;
  111. retryCount = ptpObject.retryCount;
  112. queue = ptpObject.queue;
  113. }
  114. public PtpObject(INetworkAdapter networkAdapter) {
  115. super(networkAdapter);
  116. }
  117. public pspNetMacAddress getDestMacAddress() {
  118. return destMacAddress;
  119. }
  120. public void setDestMacAddress(pspNetMacAddress destMacAddress) {
  121. this.destMacAddress = destMacAddress;
  122. }
  123. public int getDestPort() {
  124. return destPort;
  125. }
  126. public void setDestPort(int destPort) {
  127. this.destPort = destPort;
  128. }
  129. public int getRetryDelay() {
  130. return retryDelay;
  131. }
  132. public void setRetryDelay(int retryDelay) {
  133. this.retryDelay = retryDelay;
  134. }
  135. public int getRetryCount() {
  136. return retryCount;
  137. }
  138. public void setRetryCount(int retryCount) {
  139. this.retryCount = retryCount;
  140. }
  141. public int getQueue() {
  142. return queue;
  143. }
  144. public void setQueue(int queue) {
  145. this.queue = queue;
  146. }
  147. public int getSentData() {
  148. return sentData;
  149. }
  150. @Override
  151. public void openSocket() throws UnknownHostException, IOException {
  152. if (socket == null) {
  153. super.openSocket();
  154. if (getDestMacAddress() != null) {
  155. int realDestPort = Modules.sceNetAdhocModule.getRealPortFromClientPort(getDestMacAddress().macAddress, getDestPort());
  156. SocketAddress socketAddress = Modules.sceNetAdhocModule.getSocketAddress(getDestMacAddress().macAddress, realDestPort);
  157. socket.connect(socketAddress, realDestPort);
  158. }
  159. }
  160. }
  161. public int open() {
  162. int result = 0;
  163. try {
  164. openSocket();
  165. } catch (BindException e) {
  166. if (log.isDebugEnabled()) {
  167. log.debug("open", e);
  168. }
  169. result = SceKernelErrors.ERROR_NET_ADHOC_PORT_IN_USE;
  170. } catch (SocketException e) {
  171. log.error("open", e);
  172. } catch (UnknownHostException e) {
  173. log.error("open", e);
  174. } catch (IOException e) {
  175. log.error("open", e);
  176. }
  177. return result;
  178. }
  179. public int listen() {
  180. int result = 0;
  181. try {
  182. openSocket();
  183. } catch (BindException e) {
  184. if (log.isDebugEnabled()) {
  185. log.debug("listen", e);
  186. }
  187. result = SceKernelErrors.ERROR_NET_ADHOC_PORT_IN_USE;
  188. } catch (SocketException e) {
  189. log.error("listen", e);
  190. } catch (UnknownHostException e) {
  191. log.error("listen", e);
  192. } catch (IOException e) {
  193. log.error("listen", e);
  194. }
  195. return result;
  196. }
  197. public int accept(int peerMacAddr, int peerPortAddr, int timeout, int nonblock) {
  198. int result = 0;
  199. SceKernelThreadInfo thread = Modules.ThreadManForUserModule.getCurrentThread();
  200. if (pollAccept(peerMacAddr, peerPortAddr, thread)) {
  201. // Accept completed immediately
  202. result = thread.cpuContext._v0;
  203. } else if (nonblock != 0) {
  204. // Accept cannot be completed in non-blocking mode
  205. result = SceKernelErrors.ERROR_NET_ADHOC_NO_DATA_AVAILABLE;
  206. } else {
  207. // Block current thread
  208. BlockedPtpAction blockedPtpAction = new BlockedPtpAccept(this, peerMacAddr, peerPortAddr, timeout);
  209. blockedPtpAction.blockCurrentThread();
  210. }
  211. return result;
  212. }
  213. public int connect(int timeout, int nonblock) {
  214. int result = 0;
  215. if (!pollConnect(Modules.ThreadManForUserModule.getCurrentThread())) {
  216. if (nonblock != 0) {
  217. result = SceKernelErrors.ERROR_NET_ADHOC_NO_DATA_AVAILABLE;
  218. } else {
  219. BlockedPtpAction blockedPtpAction = new BlockedPtpConnect(this, timeout);
  220. blockedPtpAction.blockCurrentThread();
  221. }
  222. }
  223. return result;
  224. }
  225. @Override
  226. public void send(AdhocMessage adhocMessage) throws IOException {
  227. adhocMessage.setFromMacAddress(getMacAddress().macAddress);
  228. adhocMessage.setToMacAddress(getDestMacAddress().macAddress);
  229. send(adhocMessage, getDestPort());
  230. }
  231. public int send(int data, TPointer32 dataSizeAddr, int timeout, int nonblock) {
  232. int result = 0;
  233. try {
  234. AdhocMessage adhocMessage = networkAdapter.createAdhocPtpMessage(data, dataSizeAddr.getValue());
  235. send(adhocMessage);
  236. } catch (IOException e) {
  237. result = SceKernelErrors.ERROR_NET_ADHOC_DISCONNECTED;
  238. log.error("send returning ERROR_NET_ADHOC_DISCONNECTED", e);
  239. }
  240. return result;
  241. }
  242. // For Ptp sockets, data in read as a byte stream. Data is not organized in packets.
  243. // Read as much data as the provided buffer can contain.
  244. public int recv(TPointer data, TPointer32 dataLengthAddr, int timeout, int nonblock) {
  245. int result = 0;
  246. try {
  247. SceKernelThreadInfo thread = Modules.ThreadManForUserModule.getCurrentThread();
  248. if (pollRecv(data, dataLengthAddr, thread)) {
  249. // Recv completed immediately
  250. result = thread.cpuContext._v0;
  251. } else if (nonblock != 0) {
  252. // Recv cannot be completed in non-blocking mode
  253. result = SceKernelErrors.ERROR_NET_ADHOC_NO_DATA_AVAILABLE;
  254. } else {
  255. // Block current thread
  256. BlockedPdpAction blockedPdpAction = new BlockedPtpRecv(this, data, dataLengthAddr, timeout);
  257. blockedPdpAction.blockCurrentThread();
  258. }
  259. } catch (IOException e) {
  260. result = SceKernelErrors.ERROR_NET_ADHOC_DISCONNECTED;
  261. log.error("recv", e);
  262. }
  263. return result;
  264. }
  265. protected boolean pollRecv(TPointer data, TPointer32 dataLengthAddr, SceKernelThreadInfo thread) throws IOException {
  266. int length = dataLengthAddr.getValue();
  267. boolean completed = false;
  268. if (length > 0) {
  269. if (getRcvdData() <= 0 || receivedMessage != null) {
  270. update();
  271. }
  272. if (getRcvdData() > 0) {
  273. if (length > getRcvdData()) {
  274. length = getRcvdData();
  275. }
  276. // Copy the data already received
  277. dataLengthAddr.setValue(length);
  278. Memory mem = Memory.getInstance();
  279. mem.memcpy(data.getAddress(), buffer.addr, length);
  280. if (getRcvdData() > length) {
  281. // Shift the remaining buffer data to the beginning of the buffer
  282. mem.memmove(buffer.addr, buffer.addr + length, getRcvdData() - length);
  283. }
  284. rcvdData -= length;
  285. if (log.isDebugEnabled()) {
  286. log.debug(String.format("Returned received data: %d bytes", length));
  287. if (log.isTraceEnabled()) {
  288. log.trace(String.format("Returned data: %s", Utilities.getMemoryDump(data.getAddress(), length)));
  289. }
  290. }
  291. setReturnValue(thread, 0);
  292. completed = true;
  293. }
  294. }
  295. return completed;
  296. }
  297. // For Ptp sockets, data is stored in the internal buffer as a continuous byte stream.
  298. // The organization in packets doesn't matter.
  299. private int addReceivedMessage(AdhocMessage adhocMessage, int offset) {
  300. int length = Math.min(adhocMessage.getDataLength() - offset, getBufSize() - getRcvdData());
  301. int addr = buffer.addr + getRcvdData();
  302. adhocMessage.writeDataToMemory(addr, offset, length);
  303. rcvdData += length;
  304. if (log.isDebugEnabled()) {
  305. if (offset == 0) {
  306. log.debug(String.format("Successfully received message (length=%d, rcvdData=%d) %s", length, getRcvdData(), adhocMessage));
  307. } else {
  308. log.debug(String.format("Appending received message (offset=%d, length=%d, rcvdData=%d) %s", offset, length, getRcvdData(), adhocMessage));
  309. }
  310. if (log.isTraceEnabled()) {
  311. log.trace(String.format("Message data: %s", Utilities.getMemoryDump(addr, length)));
  312. }
  313. }
  314. return length;
  315. }
  316. @Override
  317. public void update() throws IOException {
  318. // Receive all messages available
  319. while (getRcvdData() < getBufSize()) {
  320. if (receivedMessage != null) {
  321. receivedMessageOffset += addReceivedMessage(receivedMessage, receivedMessageOffset);
  322. if (receivedMessageOffset >= receivedMessage.getDataLength()) {
  323. receivedMessage = null;
  324. receivedMessageOffset = 0;
  325. }
  326. } else {
  327. try {
  328. openSocket();
  329. socket.setTimeout(1);
  330. byte[] bytes = new byte[0x10000]; // 64K buffer
  331. int length = socket.receive(bytes, bytes.length);
  332. int receivedPort = socket.getReceivedPort();
  333. InetAddress receivedAddress = socket.getReceivedAddress();
  334. AdhocMessage adhocMessage = createAdhocMessage(bytes, length);
  335. if (isForMe(adhocMessage, receivedPort, receivedAddress)) {
  336. receivedMessage = adhocMessage;
  337. receivedMessageOffset = 0;
  338. } else {
  339. if (log.isDebugEnabled()) {
  340. log.debug(String.format("Received message not for me: %s", adhocMessage));
  341. }
  342. }
  343. } catch (SocketException e) {
  344. log.error("update", e);
  345. break;
  346. } catch (SocketTimeoutException e) {
  347. // Timeout
  348. break;
  349. }
  350. }
  351. }
  352. }
  353. @Override
  354. protected AdhocMessage createAdhocMessage(byte[] message, int length) {
  355. return networkAdapter.createAdhocPtpMessage(message, length);
  356. }
  357. protected abstract boolean pollAccept(int peerMacAddr, int peerPortAddr, SceKernelThreadInfo thread);
  358. protected abstract boolean pollConnect(SceKernelThreadInfo thread);
  359. public abstract boolean canAccept();
  360. public abstract boolean canConnect();
  361. @Override
  362. public String toString() {
  363. return String.format("PtpObject[id=%d, srcMacAddress=%s, srcPort=%d, destMacAddress=%s, destPort=%d, bufSize=%d, retryDelay=%d, retryCount=%d, queue=%d, rcvdData=%d]", getId(), getMacAddress(), getPort(), getDestMacAddress(), getDestPort(), getBufSize(), getRetryDelay(), getRetryCount(), getQueue(), getRcvdData());
  364. }
  365. }