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

/projects/jtopen-7.8/src/com/ibm/as400/access/PortMapper.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 410 lines | 330 code | 36 blank | 44 comment | 81 complexity | 8e06ebd07810bd7c6e6d82509059bfb4 MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // JTOpen (IBM Toolbox for Java - OSS version)
  4. //
  5. // Filename: PortMapper.java
  6. //
  7. // The source code contained herein is licensed under the IBM Public License
  8. // Version 1.0, which has been approved by the Open Source Initiative.
  9. // Copyright (C) 1998-2006 International Business Machines Corporation and
  10. // others. All rights reserved.
  11. //
  12. ///////////////////////////////////////////////////////////////////////////////
  13. package com.ibm.as400.access;
  14. import java.io.IOException;
  15. import java.io.InputStream;
  16. import java.io.OutputStream;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.net.InetAddress;
  20. import java.net.NoRouteToHostException;
  21. import java.net.Socket;
  22. import java.net.SocketAddress;
  23. import java.net.SocketException;
  24. import java.util.Hashtable;
  25. import java.net.InetSocketAddress;
  26. class PortMapper
  27. {
  28. private PortMapper()
  29. {
  30. }
  31. private static Hashtable systemList = new Hashtable();
  32. static void setServicePortsToDefault(String systemName)
  33. {
  34. int[] newPortList =
  35. {
  36. 8473, // 0 File.
  37. 8474, // 1 Print.
  38. 8475, // 2 Command.
  39. 8472, // 3 Data Queue.
  40. 8471, // 4 Database.
  41. 446, // 5 Record Level Access.
  42. 8470, // 6 Central.
  43. 8476, // 7 Sign-on.
  44. 9473, // 8 Secure File.
  45. 9474, // 9 Secure Print.
  46. 9475, // 10 Secure Command.
  47. 9472, // 11 Secure Data Queue.
  48. 9471, // 12 Secure Database.
  49. 448, // 13 Secure Record Level Access.
  50. 9470, // 14 Secure Central.
  51. 9476 // 15 Secure Sign-on.
  52. };
  53. systemList.put(systemName, newPortList);
  54. }
  55. static void setServicePort(String systemName, int service, int port, SSLOptions useSSL)
  56. {
  57. if (useSSL != null && useSSL.proxyEncryptionMode_ != SecureAS400.CLIENT_TO_PROXY_SERVER) service += 8;
  58. int[] portList = (int[])systemList.get(systemName);
  59. if (portList == null)
  60. {
  61. int[] newPortList =
  62. {
  63. AS400.USE_PORT_MAPPER, // 0 File.
  64. AS400.USE_PORT_MAPPER, // 1 Print.
  65. AS400.USE_PORT_MAPPER, // 2 Command.
  66. AS400.USE_PORT_MAPPER, // 3 Data Queue.
  67. AS400.USE_PORT_MAPPER, // 4 Database.
  68. 446, // 5 Record Level Access.
  69. AS400.USE_PORT_MAPPER, // 6 Central.
  70. AS400.USE_PORT_MAPPER, // 7 Sign-on.
  71. AS400.USE_PORT_MAPPER, // 8 Secure File.
  72. AS400.USE_PORT_MAPPER, // 9 Secure Print.
  73. AS400.USE_PORT_MAPPER, // 10 Secure Command.
  74. AS400.USE_PORT_MAPPER, // 11 Secure Data Queue.
  75. AS400.USE_PORT_MAPPER, // 12 Secure Database.
  76. 448, // 13 Secure Record Level Access.
  77. AS400.USE_PORT_MAPPER, // 14 Secure Central.
  78. AS400.USE_PORT_MAPPER // 15 Secure Sign-on.
  79. };
  80. newPortList[service] = port;
  81. systemList.put(systemName, newPortList);
  82. }
  83. else
  84. {
  85. portList[service] = port;
  86. }
  87. }
  88. static int getServicePort(String systemName, int service, SSLOptions useSSL)
  89. {
  90. if (useSSL != null && useSSL.proxyEncryptionMode_ != SecureAS400.CLIENT_TO_PROXY_SERVER) service += 8;
  91. int[] portList = (int[])systemList.get(systemName);
  92. if (portList == null)
  93. {
  94. if (service == AS400.RECORDACCESS)
  95. {
  96. return 446;
  97. }
  98. if (service == AS400.RECORDACCESS + 8)
  99. {
  100. return 448;
  101. }
  102. return AS400.USE_PORT_MAPPER;
  103. }
  104. return portList[service];
  105. }
  106. static boolean unixSocketAvailable = true;
  107. private static boolean canUseUnixSocket(String systemName, int service, boolean mustUseNetSockets)
  108. {
  109. if (AS400.onAS400 && unixSocketAvailable && !mustUseNetSockets && service != AS400.FILE && (systemName.equalsIgnoreCase("localhost") || systemName.equalsIgnoreCase("ipv6-localhost")))
  110. {
  111. if (service == AS400.DATABASE && AS400.nativeVRM.vrm_ < 0x00060100) return false;
  112. return true;
  113. }
  114. return false;
  115. }
  116. static SocketContainer getServerSocket(String systemName, int service, SSLOptions useSSL, SocketProperties socketProperties, boolean mustUseNetSockets) throws IOException
  117. {
  118. SocketContainer sc = null;
  119. String serviceName = AS400.getServerName(service);
  120. // If we're running on a native vm, we're requesting a service that supports a unix domain socket connection, and the unix domain socket code is accessable.
  121. if (canUseUnixSocket(systemName, service, mustUseNetSockets))
  122. {
  123. try
  124. {
  125. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Starting a local socket to " + serviceName);
  126. sc = AS400.nativeVRM.vrm_ < 0x00050400 ? (SocketContainer)AS400.loadImpl("com.ibm.as400.access.SocketContainerUnix") : (SocketContainer)AS400.loadImpl("com.ibm.as400.access.SocketContainerUnix2");
  127. if (sc != null)
  128. {
  129. sc.setProperties(null, serviceName, null, 0, null);
  130. return sc;
  131. }
  132. }
  133. catch (IOException e)
  134. {
  135. Trace.log(Trace.ERROR, "Error attempting to connect with Unix Socket:", e);
  136. sc = null;
  137. }
  138. // Only try for Unix domain connection once.
  139. unixSocketAvailable = false;
  140. }
  141. int srvPort = PortMapper.getServicePort(systemName, service, useSSL);
  142. if (srvPort == AS400.USE_PORT_MAPPER)
  143. {
  144. // Establish a socket connection to the "port mapper" through port 449...
  145. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Connecting to port mapper...");
  146. //Code to make use of new method java.net.Socket.connect(host, timeout) in jdk 1.4
  147. //only really needed on first socket connect so we do not hang when a system is down.
  148. //Socket pmSocket = new Socket(systemName, 449); //@timeout
  149. Socket pmSocket = getSocketConnection(systemName, 449, socketProperties); //@timeout2
  150. InputStream pmInstream = pmSocket.getInputStream();
  151. OutputStream pmOutstream = pmSocket.getOutputStream();
  152. // Now we construct and send a "port map" request to get the port number for the requested service...
  153. String fullServiceName = (useSSL != null && useSSL.proxyEncryptionMode_ != SecureAS400.CLIENT_TO_PROXY_SERVER) ? serviceName + "-s" : serviceName;
  154. AS400PortMapDS pmreq = new AS400PortMapDS(fullServiceName);
  155. if (Trace.traceOn_) pmreq.setConnectionID(pmSocket.hashCode());
  156. pmreq.write(pmOutstream);
  157. // Now we get the response and close the socket connection to the port mapper...
  158. AS400PortMapReplyDS pmresp = new AS400PortMapReplyDS();
  159. if (Trace.traceOn_) pmresp.setConnectionID(pmSocket.hashCode());
  160. pmresp.read(pmInstream);
  161. pmSocket.close();
  162. try
  163. {
  164. srvPort = pmresp.getPort();
  165. }
  166. catch (ServerStartupException e)
  167. {
  168. Trace.log(Trace.ERROR, "Failed to map a port for " + fullServiceName, e);
  169. throw e;
  170. }
  171. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding entry to Service Port table: system " + systemName + ", service " + fullServiceName + ", port " + srvPort);
  172. PortMapper.setServicePort(systemName, service, srvPort, useSSL);
  173. }
  174. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Opening socket to system...");
  175. Socket socket = getSocketConnection(systemName, srvPort, socketProperties); //@timeout2
  176. PortMapper.setSocketProperties(socket, socketProperties);
  177. // We use the port returned in the previous reply to establish a new socket connection to the requested service...
  178. if (useSSL != null && useSSL.proxyEncryptionMode_ != SecureAS400.CLIENT_TO_PROXY_SERVER)
  179. {
  180. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Starting a secure socket to " + serviceName);
  181. try
  182. {
  183. if (useSSL.useSslight_) throw new Exception();
  184. sc = (SocketContainer)AS400.loadImpl("com.ibm.as400.access.SocketContainerJSSE");
  185. sc.setProperties(socket, null, systemName, srvPort, null);
  186. }
  187. catch (Throwable e)
  188. {
  189. try
  190. {
  191. if (Trace.traceOn_) Trace.log(Trace.ERROR, "Exception using JSSE; falling back to SSLight:", e);
  192. sc = (SocketContainer)AS400.loadImpl("com.ibm.as400.access.SocketContainerSSL");
  193. sc.setProperties(socket, null, null, 0, useSSL);
  194. }
  195. catch (NoClassDefFoundError e1)
  196. {
  197. Trace.log(Trace.ERROR, "SSLight classes are not found on classpath.", e1);
  198. throw e1;
  199. }
  200. catch (VerifyError e1)
  201. {
  202. Trace.log(Trace.ERROR, "SSLight classes are not found on classpath.", e1);
  203. throw e1;
  204. }
  205. }
  206. }
  207. else
  208. {
  209. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Starting an inet socket to " + serviceName);
  210. sc = (SocketContainer)AS400.loadImpl("com.ibm.as400.access.SocketContainerInet");
  211. sc.setProperties(socket, null, null, 0, null);
  212. }
  213. return sc;
  214. }
  215. /* Helper method to get connection using the timeout available in jmv 1.4+
  216. * If running in JVM 1.3 then it defaults to the old connection without a timeout
  217. */
  218. static Socket getSocketConnection(String systemName, int port, SocketProperties socketProperties) throws IOException
  219. {
  220. //Code to make use of new method java.net.Socket.connect(host, timeout) in jdk 1.4
  221. //only really needed on first socket connect so we do not hang when a system is down.
  222. //Socket pmSocket = new Socket(systemName, port);
  223. Socket pmSocket = null;
  224. try
  225. {
  226. /* Due to various jvm and compile issues, there are many possible types of exceptions that could
  227. be thrown, depending on jvm version and implementation etc. Class.forName() seems to be the best
  228. solution to finding the jvm version that does not degrade performance. */
  229. Class.forName("java.net.InetSocketAddress"); //throws ClassNotFoundException (common to all jvm implementations)
  230. pmSocket = new Socket();
  231. int loginTimeout = 0;
  232. if(socketProperties.isLoginTimeoutSet())
  233. {
  234. loginTimeout = socketProperties.getLoginTimeout();
  235. }
  236. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Connect to port mapper: system '"+systemName+"', port " +port+ ", login timeout " + loginTimeout + " ms.");
  237. InetSocketAddress hostAddr = systemName != null ? new InetSocketAddress(systemName, port) :
  238. new InetSocketAddress(InetAddress.getByName(null), port);
  239. //pmSocket.connect(hostAddr, timeout); //fyi, PortMapper will not load and gets NoClassDefFoundError in jvm1.3 due to SocketAddress parameter type, must use reflection below
  240. boolean done = false;
  241. // Retry 3 times if get a bindException
  242. int bindExceptionRetries = 3;
  243. long bindExceptionRetrySleepTime=100;
  244. while (!done) // up to two tries
  245. {
  246. try
  247. {
  248. Class thisClass = pmSocket.getClass();
  249. Method method = thisClass.getMethod("connect", new Class[]{ SocketAddress.class, java.lang.Integer.TYPE});
  250. //method.setAccessible(true); //@CRS (applet gets exception when calling setAccessible())
  251. Object args[] = new Object[2];
  252. args[0] = hostAddr;
  253. args[1] = new Integer(loginTimeout);
  254. method.invoke(pmSocket, args);
  255. done = true; // if no exception thrown, then no need to try again
  256. }
  257. catch (InvocationTargetException e) {
  258. Trace.log(Trace.ERROR, e);
  259. Throwable e2 = e.getTargetException();
  260. if (e2 != null) Trace.log(Trace.ERROR, e2);
  261. // If we get a java.net.BindException then too many of the sockets are still reserved.
  262. // I've only see this when testing. Retry three times if this occurs.
  263. //
  264. if (e2 instanceof java.net.BindException) {
  265. if (bindExceptionRetries > 0) {
  266. // try again
  267. bindExceptionRetries--;
  268. try {
  269. Thread.sleep(bindExceptionRetrySleepTime);
  270. bindExceptionRetrySleepTime = bindExceptionRetrySleepTime * 2;
  271. } catch (Exception sleepException) {
  272. }
  273. done = false;
  274. } else {
  275. throw (java.net.BindException) e2;
  276. }
  277. } else if(e2 instanceof IOException)
  278. {
  279. //Here is the actual timeout or network exceptions that we throw back to caller
  280. throw (IOException) e2;
  281. }
  282. else
  283. {
  284. //Else this is some sort of issue related to reflection not being supported. Just throw ClassNotFoundException and catch it below.
  285. throw new ClassNotFoundException();
  286. }
  287. }
  288. catch (IllegalAccessException e) {
  289. //Else this is some sort of issue related to reflection not being supported. Just throw ClassNotFoundException and catch it below.
  290. Trace.log(Trace.ERROR, e);
  291. throw new ClassNotFoundException();
  292. }
  293. catch (NoSuchMethodException e) {
  294. //Else this is some sort of issue related to reflection not being supported. Just throw ClassNotFoundException and catch it below.
  295. Trace.log(Trace.ERROR, e);
  296. throw new ClassNotFoundException();
  297. }
  298. catch (Exception e) { // compiler won't let us catch "IOException"
  299. if (e instanceof NoRouteToHostException)
  300. {
  301. // If we previously specified "localhost", retry with "ipv6-localhost".
  302. if ("localhost".equalsIgnoreCase(hostAddr.getHostName()))
  303. {
  304. if (Trace.traceOn_) {
  305. Trace.log(Trace.DIAGNOSTIC, e.getMessage());
  306. Trace.log(Trace.DIAGNOSTIC, "Retrying with hostname 'ipv6-localhost' instead of 'localhost'.");
  307. }
  308. hostAddr = new InetSocketAddress("ipv6-localhost", port);
  309. done = false; // iterate the loop
  310. }
  311. else throw (NoRouteToHostException)e; // don't retry
  312. }
  313. else if (e instanceof IOException) throw (IOException)e;
  314. else throw new RuntimeException(e); // should never happen
  315. }
  316. } // while
  317. } // outer try
  318. catch(ClassNotFoundException e){
  319. //Here we catch any exception related to running in jdk 1.3 or reflection exceptions
  320. //Just create socket the way we did before without a timeout.
  321. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Connect to port mapper: system '"+systemName+"', port " +port+ ", no login timeout (JVM 1.3 or lower).");
  322. pmSocket = new Socket(systemName, port); //for pre jdk1.4
  323. }
  324. return pmSocket;
  325. }
  326. static void setSocketProperties(Socket socket, SocketProperties socketProperties) throws SocketException
  327. {
  328. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting socket options...");
  329. if (socketProperties.keepAliveSet_)
  330. {
  331. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting keep alive:", socketProperties.keepAlive_);
  332. socket.setKeepAlive(socketProperties.keepAlive_);
  333. }
  334. if (socketProperties.receiveBufferSizeSet_)
  335. {
  336. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting receive buffer size:", socketProperties.receiveBufferSize_);
  337. socket.setReceiveBufferSize(socketProperties.receiveBufferSize_);
  338. }
  339. if (socketProperties.sendBufferSizeSet_)
  340. {
  341. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting send buffer size:", socketProperties.sendBufferSize_);
  342. socket.setSendBufferSize(socketProperties.sendBufferSize_);
  343. }
  344. if (socketProperties.soLingerSet_)
  345. {
  346. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting so linger:", socketProperties.soLinger_);
  347. socket.setSoLinger(true, socketProperties.soLinger_);
  348. }
  349. if (socketProperties.soTimeoutSet_)
  350. {
  351. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting so timeout:", socketProperties.soTimeout_);
  352. socket.setSoTimeout(socketProperties.soTimeout_);
  353. }
  354. if (socketProperties.tcpNoDelaySet_)
  355. {
  356. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting TCP no delay:", socketProperties.tcpNoDelay_);
  357. socket.setTcpNoDelay(socketProperties.tcpNoDelay_);
  358. }
  359. if (Trace.traceOn_)
  360. {
  361. Trace.log(Trace.DIAGNOSTIC, "Socket properties:");
  362. try { Trace.log(Trace.DIAGNOSTIC, " Remote address: " + socket.getInetAddress()); } catch (Throwable t) {}
  363. try { Trace.log(Trace.DIAGNOSTIC, " Remote port:", socket.getPort()); } catch (Throwable t) {}
  364. try { Trace.log(Trace.DIAGNOSTIC, " Local address: " + socket.getLocalAddress()); } catch (Throwable t) {}
  365. try { Trace.log(Trace.DIAGNOSTIC, " Local port:", socket.getLocalPort()); } catch (Throwable t) {}
  366. try { Trace.log(Trace.DIAGNOSTIC, " Keep alive:", socket.getKeepAlive()); } catch (Throwable t) {}
  367. try { Trace.log(Trace.DIAGNOSTIC, " Receive buffer size:", socket.getReceiveBufferSize()); } catch (Throwable t) {}
  368. try { Trace.log(Trace.DIAGNOSTIC, " Send buffer size:", socket.getSendBufferSize()); } catch (Throwable t) {}
  369. try { Trace.log(Trace.DIAGNOSTIC, " So linger:", socket.getSoLinger()); } catch (Throwable t) {}
  370. try { Trace.log(Trace.DIAGNOSTIC, " So timeout:", socket.getSoTimeout()); } catch (Throwable t) {}
  371. try { Trace.log(Trace.DIAGNOSTIC, " TCP no delay:", socket.getTcpNoDelay()); } catch (Throwable t) {}
  372. }
  373. }
  374. }