You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TcpSocket.java 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright (C) 2012 Brian P. Hinz
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  17. * USA.
  18. */
  19. package com.tigervnc.network;
  20. import com.tigervnc.rdr.FdInStream;
  21. import com.tigervnc.rdr.FdOutStream;
  22. import com.tigervnc.rdr.Exception;
  23. import com.tigervnc.rfb.LogWriter;
  24. import java.io.IOException;
  25. import java.net.InetAddress;
  26. import java.net.InetSocketAddress;
  27. import java.net.SocketAddress;
  28. import java.net.UnknownHostException;
  29. import java.nio.*;
  30. import java.nio.channels.*;
  31. import java.util.Set;
  32. import java.util.Iterator;
  33. public class TcpSocket extends Socket {
  34. // -=- Socket initialisation
  35. public static boolean socketsInitialised = false;
  36. public static void initSockets() {
  37. if (socketsInitialised)
  38. return;
  39. socketsInitialised = true;
  40. }
  41. // -=- TcpSocket
  42. public TcpSocket(SocketDescriptor sock, boolean close) {
  43. super(new FdInStream(sock), new FdOutStream(sock), true);
  44. closeFd = close;
  45. }
  46. public TcpSocket(SocketDescriptor sock) {
  47. this(sock, true);
  48. }
  49. public TcpSocket(String host, int port) throws Exception {
  50. closeFd = true;
  51. SocketDescriptor sock = null;
  52. InetAddress addr = null;
  53. boolean result = false;
  54. // - Create a socket
  55. initSockets();
  56. try {
  57. addr = java.net.InetAddress.getByName(host);
  58. } catch(UnknownHostException e) {
  59. throw new Exception("unable to resolve host by name: "+e.toString());
  60. }
  61. try {
  62. sock = new SocketDescriptor();
  63. } catch(Exception e) {
  64. throw new SocketException("unable to create socket: "+e.toString());
  65. }
  66. /* Attempt to connect to the remote host */
  67. try {
  68. result = sock.connect(new InetSocketAddress(addr, port));
  69. Selector selector = Selector.open();
  70. SelectionKey connect_key =
  71. sock.socket().getChannel().register(selector, SelectionKey.OP_CONNECT);
  72. // Try for the connection for 3000ms
  73. while (selector.select(3000) > 0) {
  74. while (!result) {
  75. Set keys = selector.selectedKeys();
  76. Iterator i = keys.iterator();
  77. while (i.hasNext()) {
  78. SelectionKey key = (SelectionKey)i.next();
  79. // Remove the current key
  80. i.remove();
  81. // Attempt a connection
  82. if (key.isConnectable()) {
  83. if (sock.isConnectionPending())
  84. sock.finishConnect();
  85. result = true;
  86. }
  87. }
  88. }
  89. }
  90. if (!result)
  91. throw new SocketException("unable to connect to socket: Host is down");
  92. } catch(java.io.IOException e) {
  93. throw new SocketException("unable to connect:"+e.getMessage());
  94. }
  95. // Disable Nagle's algorithm, to reduce latency
  96. enableNagles(sock, false);
  97. // Create the input and output streams
  98. instream = new FdInStream(sock);
  99. outstream = new FdOutStream(sock);
  100. ownStreams = true;
  101. }
  102. protected void finalize() throws Exception {
  103. if (closeFd)
  104. try {
  105. ((SocketDescriptor)getFd()).close();
  106. } catch (IOException e) {
  107. throw new Exception(e.getMessage());
  108. }
  109. }
  110. public int getMyPort() {
  111. return getSockPort();
  112. }
  113. public String getPeerAddress() {
  114. InetAddress peer = ((SocketDescriptor)getFd()).socket().getInetAddress();
  115. if (peer != null)
  116. return peer.getHostAddress();
  117. return "";
  118. }
  119. public String getPeerName() {
  120. InetAddress peer = ((SocketDescriptor)getFd()).socket().getInetAddress();
  121. if (peer != null)
  122. return peer.getHostName();
  123. return "";
  124. }
  125. public int getPeerPort() {
  126. int port = ((SocketDescriptor)getFd()).socket().getPort();
  127. return port;
  128. }
  129. public String getPeerEndpoint() {
  130. String address = getPeerAddress();
  131. int port = getPeerPort();
  132. return address+"::"+port;
  133. }
  134. public boolean sameMachine() throws Exception {
  135. try {
  136. SocketAddress peeraddr = ((SocketDescriptor)getFd()).getRemoteAddress();
  137. SocketAddress myaddr = ((SocketDescriptor)getFd()).getLocalAddress();
  138. return myaddr.equals(peeraddr);
  139. } catch (IOException e) {
  140. throw new Exception(e.getMessage());
  141. }
  142. }
  143. public void shutdown() throws Exception {
  144. super.shutdown();
  145. try {
  146. ((SocketDescriptor)getFd()).shutdown();
  147. } catch (IOException e) {
  148. throw new Exception(e.getMessage());
  149. }
  150. }
  151. public void close() throws IOException {
  152. ((SocketDescriptor)getFd()).close();
  153. }
  154. public static boolean enableNagles(SocketDescriptor sock, boolean enable) {
  155. try {
  156. sock.channel.socket().setTcpNoDelay(!enable);
  157. } catch(java.net.SocketException e) {
  158. vlog.error("unable to setsockopt TCP_NODELAY: "+e.getMessage());
  159. return false;
  160. }
  161. return true;
  162. }
  163. public static boolean isSocket(java.net.Socket sock) {
  164. return sock.getClass().toString().equals("com.tigervnc.net.Socket");
  165. }
  166. public boolean isConnected() {
  167. return ((SocketDescriptor)getFd()).isConnected();
  168. }
  169. public int getSockPort() {
  170. return ((SocketDescriptor)getFd()).socket().getLocalPort();
  171. }
  172. /* Tunnelling support. */
  173. public static int findFreeTcpPort() {
  174. java.net.ServerSocket sock;
  175. int port;
  176. try {
  177. sock = new java.net.ServerSocket(0);
  178. port = sock.getLocalPort();
  179. sock.close();
  180. } catch (java.io.IOException e) {
  181. throw new SocketException("unable to create socket: "+e.toString());
  182. }
  183. return port;
  184. }
  185. private boolean closeFd;
  186. static LogWriter vlog = new LogWriter("TcpSocket");
  187. }