/MapMysql/src/com/mysql/jdbc/StandardSocketFactory.java
Java | 478 lines | 285 code | 104 blank | 89 comment | 62 complexity | e8936e78a314f8a40547d4cfd9e8a1fc MD5 | raw file
- /*
- Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
-
- The MySQL Connector/J is licensed under the terms of the GPLv2
- <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
- There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
- this software, see the FLOSS License Exception
- <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
- This program 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; version 2
- of the License.
- This program 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 this
- program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
- Floor, Boston, MA 02110-1301 USA
- */
- package com.mysql.jdbc;
- import java.io.IOException;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.net.InetAddress;
- import java.net.InetSocketAddress;
- import java.net.Socket;
- import java.net.SocketAddress;
- import java.net.SocketException;
- import java.net.UnknownHostException;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.Properties;
- /**
- * Socket factory for vanilla TCP/IP sockets (the standard)
- *
- * @author Mark Matthews
- */
- public class StandardSocketFactory implements SocketFactory, SocketMetadata {
- public static final String TCP_NO_DELAY_PROPERTY_NAME = "tcpNoDelay";
- public static final String TCP_KEEP_ALIVE_DEFAULT_VALUE = "true";
- public static final String TCP_KEEP_ALIVE_PROPERTY_NAME = "tcpKeepAlive";
- public static final String TCP_RCV_BUF_PROPERTY_NAME = "tcpRcvBuf";
- public static final String TCP_SND_BUF_PROPERTY_NAME = "tcpSndBuf";
- public static final String TCP_TRAFFIC_CLASS_PROPERTY_NAME = "tcpTrafficClass";
- public static final String TCP_RCV_BUF_DEFAULT_VALUE = "0";
- public static final String TCP_SND_BUF_DEFAULT_VALUE = "0";
- public static final String TCP_TRAFFIC_CLASS_DEFAULT_VALUE = "0";
- public static final String TCP_NO_DELAY_DEFAULT_VALUE = "true";
- /** Use reflection for pre-1.4 VMs */
- private static Method setTraficClassMethod;
- static {
- try {
- setTraficClassMethod = Socket.class.getMethod("setTrafficClass",
- new Class[] { Integer.TYPE });
- } catch (SecurityException e) {
- setTraficClassMethod = null;
- } catch (NoSuchMethodException e) {
- setTraficClassMethod = null;
- }
- }
- /** The hostname to connect to */
- protected String host = null;
- /** The port number to connect to */
- protected int port = 3306;
- /** The underlying TCP/IP socket to use */
- protected Socket rawSocket = null;
- /**
- * Called by the driver after issuing the MySQL protocol handshake and
- * reading the results of the handshake.
- *
- * @throws SocketException
- * if a socket error occurs
- * @throws IOException
- * if an I/O error occurs
- *
- * @return The socket to use after the handshake
- */
- public Socket afterHandshake() throws SocketException, IOException {
- return this.rawSocket;
- }
- /**
- * Called by the driver before issuing the MySQL protocol handshake. Should
- * return the socket instance that should be used during the handshake.
- *
- * @throws SocketException
- * if a socket error occurs
- * @throws IOException
- * if an I/O error occurs
- *
- * @return the socket to use before the handshake
- */
- public Socket beforeHandshake() throws SocketException, IOException {
- return this.rawSocket;
- }
- /**
- * Configures socket properties based on properties from the connection
- * (tcpNoDelay, snd/rcv buf, traffic class, etc).
- *
- * @param props
- * @throws SocketException
- * @throws IOException
- */
- private void configureSocket(Socket sock, Properties props) throws SocketException,
- IOException {
- try {
- sock.setTcpNoDelay(Boolean.valueOf(
- props.getProperty(TCP_NO_DELAY_PROPERTY_NAME,
- TCP_NO_DELAY_DEFAULT_VALUE)).booleanValue());
- String keepAlive = props.getProperty(TCP_KEEP_ALIVE_PROPERTY_NAME,
- TCP_KEEP_ALIVE_DEFAULT_VALUE);
- if (keepAlive != null && keepAlive.length() > 0) {
- sock.setKeepAlive(Boolean.valueOf(keepAlive)
- .booleanValue());
- }
- int receiveBufferSize = Integer.parseInt(props.getProperty(
- TCP_RCV_BUF_PROPERTY_NAME, TCP_RCV_BUF_DEFAULT_VALUE));
- if (receiveBufferSize > 0) {
- sock.setReceiveBufferSize(receiveBufferSize);
- }
- int sendBufferSize = Integer.parseInt(props.getProperty(
- TCP_SND_BUF_PROPERTY_NAME, TCP_SND_BUF_DEFAULT_VALUE));
- if (sendBufferSize > 0) {
- sock.setSendBufferSize(sendBufferSize);
- }
- int trafficClass = Integer.parseInt(props.getProperty(
- TCP_TRAFFIC_CLASS_PROPERTY_NAME,
- TCP_TRAFFIC_CLASS_DEFAULT_VALUE));
- if (trafficClass > 0 && setTraficClassMethod != null) {
- setTraficClassMethod.invoke(sock,
- new Object[] { Integer.valueOf(trafficClass) });
- }
- } catch (Throwable t) {
- unwrapExceptionToProperClassAndThrowIt(t);
- }
- }
- /**
- * @see com.mysql.jdbc.SocketFactory#createSocket(Properties)
- */
- public Socket connect(String hostname, int portNumber, Properties props)
- throws SocketException, IOException {
- if (props != null) {
- this.host = hostname;
- this.port = portNumber;
- Method connectWithTimeoutMethod = null;
- Method socketBindMethod = null;
- Class<?> socketAddressClass = null;
- String localSocketHostname = props
- .getProperty("localSocketAddress");
- String connectTimeoutStr = props.getProperty("connectTimeout");
- int connectTimeout = 0;
- boolean wantsTimeout = (connectTimeoutStr != null
- && connectTimeoutStr.length() > 0 && !connectTimeoutStr
- .equals("0"));
- boolean wantsLocalBind = (localSocketHostname != null && localSocketHostname
- .length() > 0);
- boolean needsConfigurationBeforeConnect = socketNeedsConfigurationBeforeConnect(props);
-
- if (wantsTimeout || wantsLocalBind || needsConfigurationBeforeConnect) {
- if (connectTimeoutStr != null) {
- try {
- connectTimeout = Integer.parseInt(connectTimeoutStr);
- } catch (NumberFormatException nfe) {
- throw new SocketException("Illegal value '"
- + connectTimeoutStr + "' for connectTimeout");
- }
- }
- try {
- // Have to do this with reflection, otherwise older JVMs
- // croak
- socketAddressClass = Class
- .forName("java.net.SocketAddress");
- connectWithTimeoutMethod = Socket.class.getMethod(
- "connect", new Class[] { socketAddressClass,
- Integer.TYPE });
- socketBindMethod = Socket.class.getMethod("bind",
- new Class[] { socketAddressClass });
- } catch (NoClassDefFoundError noClassDefFound) {
- // ignore, we give a better error below if needed
- } catch (NoSuchMethodException noSuchMethodEx) {
- // ignore, we give a better error below if needed
- } catch (Throwable catchAll) {
- // ignore, we give a better error below if needed
- }
- if (wantsLocalBind && socketBindMethod == null) {
- throw new SocketException(
- "Can't specify \"localSocketAddress\" on JVMs older than 1.4");
- }
- if (wantsTimeout && connectWithTimeoutMethod == null) {
- throw new SocketException(
- "Can't specify \"connectTimeout\" on JVMs older than 1.4");
- }
- }
- if (this.host != null) {
- if (!(wantsLocalBind || wantsTimeout || needsConfigurationBeforeConnect)) {
- InetAddress[] possibleAddresses = InetAddress
- .getAllByName(this.host);
- Throwable caughtWhileConnecting = null;
- // Need to loop through all possible addresses, in case
- // someone has IPV6 configured (SuSE, for example...)
- for (int i = 0; i < possibleAddresses.length; i++) {
- try {
- this.rawSocket = new Socket(possibleAddresses[i],
- port);
- configureSocket(this.rawSocket, props);
- break;
- } catch (Exception ex) {
- caughtWhileConnecting = ex;
- }
- }
- if (rawSocket == null) {
- unwrapExceptionToProperClassAndThrowIt(caughtWhileConnecting);
- }
- } else {
- // must explicitly state this due to classloader issues
- // when running on older JVMs :(
- try {
- InetAddress[] possibleAddresses = InetAddress
- .getAllByName(this.host);
- Throwable caughtWhileConnecting = null;
- Object localSockAddr = null;
- Class<?> inetSocketAddressClass = null;
- Constructor<?> addrConstructor = null;
- try {
- inetSocketAddressClass = Class
- .forName("java.net.InetSocketAddress");
- addrConstructor = inetSocketAddressClass
- .getConstructor(new Class[] {
- InetAddress.class, Integer.TYPE });
- if (wantsLocalBind) {
- localSockAddr = addrConstructor
- .newInstance(new Object[] {
- InetAddress
- .getByName(localSocketHostname),
- new Integer(0 /*
- * use ephemeral
- * port
- */) });
- }
- } catch (Throwable ex) {
- unwrapExceptionToProperClassAndThrowIt(ex);
- }
- // Need to loop through all possible addresses, in case
- // someone has IPV6 configured (SuSE, for example...)
- for (int i = 0; i < possibleAddresses.length; i++) {
- try {
- this.rawSocket = new Socket();
- configureSocket(this.rawSocket, props);
- Object sockAddr = addrConstructor
- .newInstance(new Object[] {
- possibleAddresses[i],
- Integer.valueOf(port) });
- // bind to the local port if not using the ephemeral port
- if (localSockAddr != null) {
- socketBindMethod.invoke(rawSocket,
- new Object[] { localSockAddr });
- }
- connectWithTimeoutMethod.invoke(rawSocket,
- new Object[] { sockAddr,
- Integer.valueOf(connectTimeout) });
- break;
- } catch (Exception ex) {
- this.rawSocket = null;
- caughtWhileConnecting = ex;
- }
- }
- if (this.rawSocket == null) {
- unwrapExceptionToProperClassAndThrowIt(caughtWhileConnecting);
- }
- } catch (Throwable t) {
- unwrapExceptionToProperClassAndThrowIt(t);
- }
- }
- return this.rawSocket;
- }
- }
- throw new SocketException("Unable to create socket");
- }
- /**
- * Does the configureSocket() need to be called before the socket is
- * connect()d based on the properties supplied?
- *
- */
- private boolean socketNeedsConfigurationBeforeConnect(Properties props) {
- int receiveBufferSize = Integer.parseInt(props.getProperty(
- TCP_RCV_BUF_PROPERTY_NAME, TCP_RCV_BUF_DEFAULT_VALUE));
- if (receiveBufferSize > 0) {
- return true;
- }
- int sendBufferSize = Integer.parseInt(props.getProperty(
- TCP_SND_BUF_PROPERTY_NAME, TCP_SND_BUF_DEFAULT_VALUE));
- if (sendBufferSize > 0) {
- return true;
- }
- int trafficClass = Integer.parseInt(props.getProperty(
- TCP_TRAFFIC_CLASS_PROPERTY_NAME,
- TCP_TRAFFIC_CLASS_DEFAULT_VALUE));
- if (trafficClass > 0 && setTraficClassMethod != null) {
- return true;
- }
- return false;
- }
- private void unwrapExceptionToProperClassAndThrowIt(
- Throwable caughtWhileConnecting) throws SocketException,
- IOException {
- if (caughtWhileConnecting instanceof InvocationTargetException) {
- // Replace it with the target, don't use 1.4 chaining as this still
- // needs to run on older VMs
- caughtWhileConnecting = ((InvocationTargetException) caughtWhileConnecting)
- .getTargetException();
- }
- if (caughtWhileConnecting instanceof SocketException) {
- throw (SocketException) caughtWhileConnecting;
- }
- if (caughtWhileConnecting instanceof IOException) {
- throw (IOException) caughtWhileConnecting;
- }
- throw new SocketException(caughtWhileConnecting.toString());
- }
- public static final String IS_LOCAL_HOSTNAME_REPLACEMENT_PROPERTY_NAME = "com.mysql.jdbc.test.isLocalHostnameReplacement";
-
- public boolean isLocallyConnected(com.mysql.jdbc.ConnectionImpl conn)
- throws SQLException {
- long threadId = conn.getId();
- java.sql.Statement processListStmt = conn.getMetadataSafeStatement();
- ResultSet rs = null;
- try {
- String processHost = null;
- rs = processListStmt.executeQuery("SHOW PROCESSLIST");
- while (rs.next()) {
- long id = rs.getLong(1);
- if (threadId == id) {
- processHost = rs.getString(3);
- break;
- }
- }
- // "inject" for tests
- if (System.getProperty(IS_LOCAL_HOSTNAME_REPLACEMENT_PROPERTY_NAME) != null) {
- processHost = System
- .getProperty(IS_LOCAL_HOSTNAME_REPLACEMENT_PROPERTY_NAME);
- } else if (conn.getProperties().getProperty(IS_LOCAL_HOSTNAME_REPLACEMENT_PROPERTY_NAME) != null) {
- processHost = conn.getProperties().getProperty(IS_LOCAL_HOSTNAME_REPLACEMENT_PROPERTY_NAME);
- }
- if (processHost != null) {
- if (processHost.indexOf(":") != -1) {
- processHost = processHost.split(":")[0];
- try {
- boolean isLocal = false;
- InetAddress whereMysqlThinksIConnectedFrom = InetAddress.getByName(processHost);
- SocketAddress remoteSocketAddr = rawSocket.getRemoteSocketAddress();
-
- if (remoteSocketAddr instanceof InetSocketAddress) {
- InetAddress whereIConnectedTo = ((InetSocketAddress)remoteSocketAddr).getAddress();
-
- isLocal = whereMysqlThinksIConnectedFrom.equals(whereIConnectedTo);
- }
-
- return isLocal;
- } catch (UnknownHostException e) {
- conn.getLog().logWarn(
- Messages.getString(
- "Connection.CantDetectLocalConnect",
- new Object[] { host }), e);
- return false;
- }
- }
- }
- return false;
- } finally {
- processListStmt.close();
- }
- }
- }