PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/org.xerela.net.tftp/src/org/xerela/nio/nioagent/datagram/ClientDatagramAttachment.java

http://xerela.googlecode.com/
Java | 198 lines | 145 code | 20 blank | 33 comment | 10 complexity | 1e162d49b2c4885039ba668d47b16cfc MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, JSON, Apache-2.0, IPL-1.0
  1. /*
  2. * The contents of this file are subject to the Mozilla Public License
  3. * Version 1.1 (the "License"); you may not use this file except in
  4. * compliance with the License. You may obtain a copy of the License at
  5. * http://www.mozilla.org/MPL/
  6. *
  7. * Software distributed under the License is distributed on an "AS IS"
  8. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  9. * License for the specific language governing rights and limitations
  10. * under the License.
  11. *
  12. * The Original Code is Ziptie Client Framework.
  13. *
  14. * The Initial Developer of the Original Code is AlterPoint.
  15. * Portions created by AlterPoint are Copyright (C) 2006,
  16. * AlterPoint, Inc. All Rights Reserved.
  17. *
  18. * Contributor(s):
  19. */
  20. package org.xerela.nio.nioagent.datagram;
  21. import java.io.IOException;
  22. import java.net.InetSocketAddress;
  23. import java.net.SocketAddress;
  24. import java.nio.ByteBuffer;
  25. import java.nio.channels.DatagramChannel;
  26. import java.nio.channels.SelectionKey;
  27. import org.xerela.nio.common.ILogger;
  28. import org.xerela.nio.nioagent.ChannelWriter;
  29. import org.xerela.nio.nioagent.SharedBuffer;
  30. import org.xerela.nio.nioagent.WrapperException;
  31. import org.xerela.nio.nioagent.Interfaces.KeyAttachment;
  32. /**
  33. * An implementation of the KeyAttachment interface intended for the client
  34. * portion of datagram protocols that use random high ports for their
  35. * connections after the initial request is sent to the server on a well-known
  36. * port. Instances of this class contain a DatagramAttachment which is used
  37. * after the initial request is sent to the server.
  38. *
  39. * @author Brian Edwards (bedwards@alterpoint.com)
  40. *
  41. */
  42. public class ClientDatagramAttachment implements KeyAttachment
  43. {
  44. // -- static fields
  45. private final ILogger logger;
  46. private final SharedBuffer out;
  47. private final SharedBuffer in;
  48. private final byte[] outArr;
  49. private final int outLen;
  50. private final byte[] inArr;
  51. private final SocketAddress serverAddr;
  52. private final SharedBuffer.User sendUser;
  53. private final SharedBuffer.User receiveUser;
  54. private final ChannelWriter writer;
  55. private final DatagramAttachment att;
  56. private boolean isInitialConnection;
  57. private SelectionKey key;
  58. // -- constructors
  59. public ClientDatagramAttachment(final byte[] initOutArr, final int initOutLen, final SocketAddress serverAddress, final ChannelWriter writer,
  60. final ILogger logger, final Integer bufferSize)
  61. {
  62. this.logger = logger;
  63. this.out = SharedBuffer.getOutboundBuffer(logger, bufferSize);
  64. this.in = SharedBuffer.getInboundBuffer(logger, bufferSize);
  65. this.outArr = initOutArr;
  66. this.outLen = initOutLen;
  67. this.inArr = SharedBuffer.getInboundBuffer(logger, bufferSize).createByteArray();
  68. this.serverAddr = serverAddress;
  69. this.sendUser = new SendUser();
  70. this.receiveUser = new ReceiveUser();
  71. this.writer = writer;
  72. this.att = new DatagramAttachment(writer, logger, bufferSize);
  73. this.isInitialConnection = true;
  74. this.key = null;
  75. }
  76. // -- public methods
  77. public void control(SelectionKey sKey)
  78. {
  79. key = sKey;
  80. if (isInitialConnection)
  81. {
  82. if (key.isValid() && key.isWritable())
  83. {
  84. out.use(sendUser);
  85. }
  86. if (key.isValid() && key.isReadable())
  87. {
  88. in.use(receiveUser);
  89. isInitialConnection = false;
  90. }
  91. }
  92. else
  93. {
  94. att.control(key);
  95. }
  96. }
  97. // -- Inner classes
  98. private class SendUser implements SharedBuffer.User
  99. {
  100. public void use(ByteBuffer buf)
  101. {
  102. buf.put(outArr, 0, outLen);
  103. buf.flip();
  104. sendChannel((DatagramChannel) key.channel(), buf);
  105. if (buf.hasRemaining())
  106. {
  107. String msg = "Partial channel send.";
  108. logger.error(msg);
  109. key.cancel();
  110. throw new RuntimeException(msg);
  111. }
  112. else
  113. {
  114. key.interestOps(SelectionKey.OP_READ);
  115. }
  116. }
  117. private void sendChannel(DatagramChannel chan, ByteBuffer buf)
  118. {
  119. try
  120. {
  121. chan.send(buf, serverAddr);
  122. }
  123. catch (IOException e)
  124. {
  125. logger.error("Failed to send to datagram channel.");
  126. key.cancel();
  127. throw new WrapperException(e);
  128. }
  129. }
  130. }
  131. private class ReceiveUser implements SharedBuffer.User
  132. {
  133. public void use(ByteBuffer buf)
  134. {
  135. DatagramChannel chan = ((DatagramChannel) key.channel());
  136. InetSocketAddress serverAddr = (InetSocketAddress) receive(chan, buf);
  137. if (0 == buf.position() || null == serverAddr)
  138. {
  139. throw new RuntimeException("Failed to receive initial response packet from server.");
  140. }
  141. logger.debug("Client received datagram from server at " + serverAddr + ".");
  142. connect(chan, serverAddr);
  143. buf.flip();
  144. buf.get(inArr, 0, buf.limit());
  145. writer.direct(key, local(chan), serverAddr, inArr, buf.limit());
  146. }
  147. private SocketAddress receive(DatagramChannel chan, ByteBuffer buf)
  148. {
  149. try
  150. {
  151. return chan.receive(buf);
  152. }
  153. catch (IOException e)
  154. {
  155. logger.error("Failed to receive from datagram channel.");
  156. key.cancel();
  157. throw new WrapperException(e);
  158. }
  159. }
  160. private void connect(DatagramChannel chan, SocketAddress serverDataAddr)
  161. {
  162. try
  163. {
  164. chan.connect(serverDataAddr);
  165. }
  166. catch (IOException e)
  167. {
  168. logger.error("Failed to connect datagram channel to server data address " + serverDataAddr);
  169. key.cancel();
  170. throw new WrapperException(e);
  171. }
  172. }
  173. private InetSocketAddress local(DatagramChannel chan)
  174. {
  175. return (InetSocketAddress) chan.socket().getLocalSocketAddress();
  176. }
  177. }
  178. }