--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.drda.NetworkServerControlImpl\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.drda;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.DataOutputStream;\r
+import java.io.FilterOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.PrintStream;\r
+import java.io.PrintWriter;\r
+import java.net.InetAddress;\r
+import java.net.ServerSocket;\r
+import java.net.Socket;\r
+import javax.net.SocketFactory;\r
+import javax.net.ServerSocketFactory;\r
+import javax.net.ssl.SSLServerSocket;\r
+import javax.net.ssl.SSLSocket;\r
+import javax.net.ssl.SSLSocketFactory;\r
+import javax.net.ssl.SSLServerSocketFactory;\r
+import java.net.UnknownHostException;\r
+import java.security.AccessController;\r
+import java.security.PrivilegedAction;\r
+import java.security.PrivilegedActionException;\r
+import java.security.PrivilegedExceptionAction;\r
+import java.sql.Connection;\r
+import java.sql.Driver;\r
+import java.sql.DriverManager;\r
+import java.sql.SQLException;\r
+import java.sql.SQLWarning;\r
+import java.util.ArrayList;\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.Properties;\r
+import java.util.StringTokenizer;\r
+import java.util.Vector;\r
+\r
+import org.apache.derby.drda.NetworkServerControl;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.jdbc.DRDAServerStarter;\r
+import org.apache.derby.iapi.reference.Attribute;\r
+import org.apache.derby.iapi.reference.DRDAConstants;\r
+import org.apache.derby.iapi.reference.Property;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.iapi.services.info.JVMInfo;\r
+import org.apache.derby.iapi.services.info.ProductGenusNames;\r
+import org.apache.derby.iapi.services.info.ProductVersionHolder;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.property.PropertyUtil;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.tools.i18n.LocalizedOutput;\r
+import org.apache.derby.iapi.tools.i18n.LocalizedResource;\r
+import org.apache.derby.iapi.util.CheapDateFormatter;\r
+import org.apache.derby.iapi.util.StringUtil;\r
+import org.apache.derby.impl.jdbc.EmbedSQLException;\r
+\r
+/** \r
+ \r
+ NetworkServerControlImpl does all the work for NetworkServerControl\r
+ @see NetworkServerControl for description\r
+\r
+*/\r
+public final class NetworkServerControlImpl {\r
+ private final static int NO_USAGE_MSGS= 12;\r
+ private final static String [] COMMANDS = \r
+ {"start","shutdown","trace","tracedirectory","ping", \r
+ "logconnections", "sysinfo", "runtimeinfo", "maxthreads", "timeslice"};\r
+ // number of required arguments for each command\r
+ private final static int [] COMMAND_ARGS =\r
+ {0, 0, 1, 1, 0, 1, 0, 0, 1, 1};\r
+ public final static int COMMAND_START = 0;\r
+ public final static int COMMAND_SHUTDOWN = 1;\r
+ public final static int COMMAND_TRACE = 2;\r
+ public final static int COMMAND_TRACEDIRECTORY = 3;\r
+ public final static int COMMAND_TESTCONNECTION = 4;\r
+ public final static int COMMAND_LOGCONNECTIONS = 5;\r
+ public final static int COMMAND_SYSINFO = 6;\r
+ public final static int COMMAND_RUNTIME_INFO = 7;\r
+ public final static int COMMAND_MAXTHREADS = 8;\r
+ public final static int COMMAND_TIMESLICE = 9;\r
+ public final static int COMMAND_PROPERTIES = 10;\r
+ public final static int COMMAND_UNKNOWN = -1;\r
+ public final static String [] DASHARGS =\r
+ {"p","d","u","ld","ea","ep", "b", "h", "s", "noSecurityManager", "ssl"};\r
+ public final static int DASHARG_PORT = 0;\r
+ public final static int DASHARG_DATABASE = 1;\r
+ public final static int DASHARG_USER = 2;\r
+ public final static int DASHARG_LOADSYSIBM = 3;\r
+ public final static int DASHARG_ENCALG = 4;\r
+ public final static int DASHARG_ENCPRV = 5;\r
+ public final static int DASHARG_BOOTPASSWORD = 6;\r
+ public final static int DASHARG_HOST = 7;\r
+ public final static int DASHARG_SESSION = 8;\r
+ public final static int DASHARG_UNSECURE = 9;\r
+ private final static int DASHARG_SSL = 10;\r
+\r
+ // command protocol version - you need to increase this number each time\r
+ // the command protocol changes \r
+ private final static int PROTOCOL_VERSION = 1;\r
+ private final static String COMMAND_HEADER = "CMD:";\r
+ private final static String REPLY_HEADER = "RPY:";\r
+ private final static int REPLY_HEADER_LENGTH = REPLY_HEADER.length();\r
+ private final static int OK = 0;\r
+ private final static int WARNING = 1;\r
+ private final static int ERROR = 2;\r
+ private final static int SQLERROR = 3;\r
+ private final static int SQLWARNING = 4;\r
+\r
+ private final static String DRDA_PROP_MESSAGES = "org.apache.derby.loc.drda.messages";\r
+ private final static String DRDA_PROP_DEBUG = "derby.drda.debug";\r
+ private final static String CLOUDSCAPE_DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";\r
+\r
+ public final static String UNEXPECTED_ERR = "Unexpected exception";\r
+\r
+ private final static int MIN_MAXTHREADS = -1;\r
+ private final static int MIN_TIMESLICE = -1;\r
+ private final static int USE_DEFAULT = -1;\r
+ private final static int DEFAULT_MAXTHREADS = 0; //for now create whenever needed\r
+ private final static int DEFAULT_TIMESLICE = 0; //for now never yield\r
+\r
+ private final static String DEFAULT_HOST = "localhost";\r
+ private final static String DRDA_MSG_PREFIX = "DRDA_";\r
+ private final static String DEFAULT_LOCALE= "en";\r
+ private final static String DEFAULT_LOCALE_COUNTRY="US";\r
+\r
+ // Check up to 10 seconds to see if shutdown occurred\r
+ private final static int SHUTDOWN_CHECK_ATTEMPTS = 100;\r
+ private final static int SHUTDOWN_CHECK_INTERVAL= 100;\r
+\r
+ // maximum reply size\r
+ private final static int MAXREPLY = 32767;\r
+\r
+ // Application Server Attributes.\r
+ protected static String att_srvclsnm;\r
+ protected final static String ATT_SRVNAM = "NetworkServerControl";\r
+\r
+ protected static String att_extnam;\r
+ protected static String att_srvrlslv; \r
+ protected static String prdId;\r
+ protected static byte[] prdIdBytes_;\r
+ \r
+ private static String buildNumber;\r
+ private static String versionString;\r
+ // we will use single or mixed, not double byte to reduce traffic on the\r
+ // wire, this is in keeping with JCC\r
+ // Note we specify UTF8 for the single byte encoding even though it can\r
+ // be multi-byte.\r
+ protected final static int CCSIDSBC = 1208; //use UTF8\r
+ protected final static int CCSIDMBC = 1208; //use UTF8\r
+ protected final static String DEFAULT_ENCODING = "UTF8"; // use UTF8 for writing\r
+ protected final static int DEFAULT_CCSID = 1208;\r
+ protected final static byte SPACE_CHAR = 32;\r
+ \r
+\r
+ // Application Server manager levels - this needs to be in sync\r
+ // with CodePoint.MGR_CODEPOINTS\r
+ protected final static int [] MGR_LEVELS = { 7, // AGENT\r
+ 4, // CCSID Manager\r
+ 0, // CNMAPPC not implemented\r
+ 0, // CMNSYNCPT not implemented\r
+ 5, // CMNTCPIP\r
+ 0, // DICTIONARY\r
+ 7, // RDB\r
+ 0, // RSYNCMGR\r
+ 7, // SECMGR\r
+ 7, // SQLAM\r
+ 0, // SUPERVISOR\r
+ 0, // SYNCPTMGR\r
+ 7 // XAMGR\r
+ };\r
+ \r
+ \r
+ protected PrintWriter logWriter; // console\r
+ protected PrintWriter cloudscapeLogWriter; // derby.log\r
+ private static Driver cloudscapeDriver;\r
+\r
+ // error types\r
+ private final static int ERRTYPE_SEVERE = 1;\r
+ private final static int ERRTYPE_USER = 2;\r
+ private final static int ERRTYPE_INFO = 3;\r
+ private final static int ERRTYPE_UNKNOWN = -1;\r
+\r
+ // command argument information\r
+ private Vector commandArgs = new Vector();\r
+ private String databaseArg;\r
+ private String userArg;\r
+ private String passwordArg;\r
+ private String bootPasswordArg;\r
+ private String encAlgArg;\r
+ private String encPrvArg;\r
+ private String hostArg = DEFAULT_HOST; \r
+ private InetAddress hostAddress;\r
+ private int sessionArg;\r
+ private boolean unsecureArg;\r
+\r
+ // Used to debug memory in SanityManager.DEBUG mode\r
+ private memCheck mc;\r
+\r
+ // reply buffer\r
+ private byte [] replyBuffer; \r
+ private int replyBufferCount; //length of reply\r
+ private int replyBufferPos; //current position in reply\r
+\r
+ //\r
+ // server configuration\r
+ //\r
+ // static values - set at start can't be changed once server has started\r
+ private int portNumber = NetworkServerControl.DEFAULT_PORTNUMBER; // port server listens to\r
+\r
+ // configurable values\r
+ private String traceDirectory; // directory to place trace files in\r
+ private Object traceDirectorySync = new Object();// object to use for syncing\r
+ private boolean traceAll; // trace all sessions\r
+ private Object traceAllSync = new Object(); // object to use for syncing reading\r
+ // and changing trace all\r
+ private Object serverStartSync = new Object(); // for syncing start of server.\r
+ private boolean logConnections; // log connects\r
+ private Object logConnectionsSync = new Object(); // object to use for syncing \r
+ // logConnections value\r
+ private int minThreads; // default minimum number of connection threads\r
+ private int maxThreads; // default maximum number of connection threads\r
+ private Object threadsSync = new Object(); // object to use for syncing reading\r
+ // and changing default min and max threads\r
+ private int timeSlice; // default time slice of a session to a thread\r
+ private Object timeSliceSync = new Object();// object to use for syncing reading\r
+ // and changing timeSlice\r
+\r
+ private boolean keepAlive = true; // keepAlive value for client socket \r
+ private int minPoolSize; //minimum pool size for pooled connections\r
+ private int maxPoolSize; //maximum pool size for pooled connections\r
+ private Object poolSync = new Object(); // object to use for syning reading\r
+\r
+ protected boolean debugOutput = false;\r
+ private boolean cleanupOnStart = false; // Should we clean up when starting the server?\r
+ private boolean restartFlag = false;\r
+\r
+ protected final static int INVALID_OR_NOTSET_SECURITYMECHANISM = -1; \r
+ // variable to store value set to derby.drda.securityMechanism\r
+ // default value is -1 which indicates that this property isnt set or\r
+ // the value is invalid\r
+ private int allowOnlySecurityMechanism = INVALID_OR_NOTSET_SECURITYMECHANISM;\r
+ //\r
+ // variables for a client command session\r
+ //\r
+ private Socket clientSocket = null;\r
+ private InputStream clientIs = null;\r
+ private OutputStream clientOs = null;\r
+ private ByteArrayOutputStream byteArrayOs = new ByteArrayOutputStream();\r
+ private DataOutputStream commandOs = new DataOutputStream(byteArrayOs);\r
+ \r
+ private Object shutdownSync = new Object();\r
+ private boolean shutdown;\r
+ private int connNum; // number of connections since server started\r
+ private ServerSocket serverSocket;\r
+ private NetworkServerControlImpl serverInstance;\r
+ private LocalizedResource langUtil;\r
+ public String clientLocale;\r
+ ArrayList localAddresses; // list of local addresses for checking admin\r
+ // commands. \r
+\r
+ // open sessions\r
+ private Hashtable sessionTable = new Hashtable();\r
+\r
+ // current session\r
+ private Session currentSession;\r
+ // DRDAConnThreads\r
+ private Vector threadList = new Vector();\r
+\r
+ // queue of sessions waiting for a free thread - the queue is managed\r
+ // in a simple first come, first serve manner - no priorities\r
+ private Vector runQueue = new Vector();\r
+\r
+ // number of DRDAConnThreads waiting for something to do\r
+ private int freeThreads;\r
+\r
+ // known application requesters\r
+ private Hashtable appRequesterTable = new Hashtable();\r
+\r
+ // accessed by inner classes for privileged action\r
+ private String propertyFileName;\r
+ private NetworkServerControlImpl thisControl = this;\r
+\r
+ // if the server is started from the command line, it should shutdown the\r
+ // databases it has booted.\r
+ private boolean shutdownDatabasesOnShutdown = false;\r
+\r
+ // SSL related stuff\r
+ private static final int SSL_OFF = 0;\r
+ private static final int SSL_BASIC = 1;\r
+ private static final int SSL_PEER_AUTHENTICATION = 2;\r
+\r
+ private int sslMode = SSL_OFF;\r
+\r
+ /**\r
+ * Can EUSRIDPWD security mechanism be used with \r
+ * the current JVM\r
+ */\r
+ private static boolean SUPPORTS_EUSRIDPWD = false;\r
+\r
+ /*\r
+ * DRDA Specification for the EUSRIDPWD security mechanism\r
+ * requires DH algorithm support with a 32-byte prime to be\r
+ * used. Not all JCE implementations have support for this.\r
+ * Hence here we need to find out if EUSRIDPWD can be used\r
+ * with the current JVM.\r
+ */ \r
+ static\r
+ {\r
+ try\r
+ {\r
+ // The DecryptionManager class will instantiate objects of the required \r
+ // security algorithms that are needed for EUSRIDPWD\r
+ // An exception will be thrown if support is not available\r
+ // in the JCE implementation in the JVM in which the server\r
+ // is started.\r
+ new DecryptionManager();\r
+ SUPPORTS_EUSRIDPWD = true;\r
+ }catch(Exception e)\r
+ {\r
+ // if an exception is thrown, ignore exception.\r
+ // set SUPPORTS_EUSRIDPWD to false indicating that the server \r
+ // does not have support for EUSRIDPWD security mechanism\r
+ SUPPORTS_EUSRIDPWD = false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the host where we listen for connections.\r
+ */\r
+ public String getHost() { return hostArg; }\r
+\r
+ /**\r
+ * Return true if the customer forcibly overrode our decision to install a\r
+ * default SecurityManager.\r
+ */\r
+ public boolean runningUnsecure() { return unsecureArg; }\r
+ \r
+ // constructor\r
+ public NetworkServerControlImpl() throws Exception\r
+ {\r
+ init();\r
+ getPropertyInfo();\r
+ }\r
+\r
+\r
+ /**\r
+ * Internal constructor for NetworkServerControl API. \r
+ * @param address - InetAddress to listen on, May not be null. Throws NPE if null\r
+ * @param portNumber - portNumber to listen on, -1 use propert or default.\r
+ * @throws Exception on error\r
+ * @see NetworkServerControl\r
+ */\r
+ public NetworkServerControlImpl(InetAddress address, int portNumber) throws Exception\r
+ {\r
+ init();\r
+ getPropertyInfo();\r
+ this.hostAddress = address;\r
+ this.portNumber = (portNumber <= 0) ?\r
+ this.portNumber: portNumber;\r
+ this.hostArg = address.getHostAddress();\r
+ }\r
+\r
+ private void init() throws Exception\r
+ {\r
+\r
+ // adjust the application in accordance with derby.ui.locale and derby.ui.codeset\r
+ langUtil = new LocalizedResource(null,null,DRDA_PROP_MESSAGES);\r
+\r
+ serverInstance = this;\r
+ \r
+ //set Server attributes to be used in EXCSAT\r
+ ProductVersionHolder myPVH = getNetProductVersionHolder();\r
+ att_extnam = ATT_SRVNAM + " " + java.lang.Thread.currentThread().getName();\r
+ \r
+ att_srvclsnm = myPVH.getProductName();\r
+ versionString = myPVH.getVersionBuildString(true);\r
+ \r
+ String majorStr = String.valueOf(myPVH.getMajorVersion());\r
+ String minorStr = String.valueOf(myPVH.getMinorVersion());\r
+ // Maintenance version. Server protocol version.\r
+ // Only changed if client needs to recognize a new server version.\r
+ String drdaMaintStr = String.valueOf(myPVH.getDrdaMaintVersion());\r
+\r
+ // PRDID format as JCC expects it: CSSMMmx\r
+ // MM = major version\r
+ // mm = minor version\r
+ // x = drda MaintenanceVersion\r
+\r
+ prdId = DRDAConstants.DERBY_DRDA_SERVER_ID;\r
+ if (majorStr.length() == 1)\r
+ prdId += "0";\r
+ prdId += majorStr;\r
+\r
+ if (minorStr.length() == 1)\r
+ prdId += "0";\r
+\r
+ prdId += minorStr;\r
+ \r
+ prdId += drdaMaintStr;\r
+ att_srvrlslv = prdId + "/" + myPVH.getVersionBuildString(true);\r
+ // Precompute this to save some cycles\r
+ prdIdBytes_ = prdId.getBytes(DEFAULT_ENCODING);\r
+ \r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (majorStr.length() > 2 || \r
+ minorStr.length() > 2 || \r
+ drdaMaintStr.length() > 1)\r
+ SanityManager.THROWASSERT("version values out of expected range for PRDID");\r
+ }\r
+\r
+ buildNumber = myPVH.getBuildNumber();\r
+ }\r
+\r
+ private PrintWriter makePrintWriter( OutputStream out)\r
+ {\r
+ if (out != null)\r
+ return new PrintWriter(out, true /* flush the buffer at the end of each line */);\r
+ else\r
+ return null;\r
+ }\r
+\r
+ protected static Driver getDriver()\r
+ {\r
+ return cloudscapeDriver;\r
+ }\r
+ \r
+\r
+ /********************************************************************************\r
+ * Implementation of NetworkServerControl API\r
+ * The server commands throw exceptions for errors, so that users can handle\r
+ * them themselves in addition to having the errors written to the console\r
+ * and possibly derby.log. To turn off logging the errors to the console,\r
+ * set the output writer to null.\r
+ ********************************************************************************/\r
+\r
+\r
+ /**\r
+ * Set the output stream for console messages\r
+ * If this is set to null, no messages will be written to the console\r
+ *\r
+ * @param outWriter output stream for console messages\r
+ */\r
+ public void setLogWriter(PrintWriter outWriter)\r
+ {\r
+ // wrap the user-set outWriter with, autoflush to true.\r
+ // this will ensure that messages to console will be \r
+ // written out to the outWriter on a println.\r
+ // DERBY-1466\r
+ if ( outWriter != null )\r
+ logWriter = new PrintWriter(outWriter,true);\r
+ else\r
+ logWriter = outWriter;\r
+ }\r
+\r
+\r
+ \r
+ /**\r
+ * Write an error message to console output stream\r
+ * and throw an exception for this error\r
+ *\r
+ * @param msg error message\r
+ * @exception Exception\r
+ */\r
+ public void consoleError(String msg)\r
+ throws Exception\r
+ {\r
+ consoleMessage(msg);\r
+ throw new Exception(msg);\r
+ }\r
+\r
+ /**\r
+ * Write an exception to console output stream,\r
+ * but only if debugOutput is true.\r
+ *\r
+ * @param e exception \r
+ */\r
+ public void consoleExceptionPrint(Exception e)\r
+ {\r
+ if (debugOutput == true)\r
+ consoleExceptionPrintTrace(e);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Write an exception (with trace) to console\r
+ * output stream.\r
+ *\r
+ * @param e exception \r
+ */\r
+ public void consoleExceptionPrintTrace(Throwable e)\r
+ {\r
+ consoleMessage(e.getMessage());\r
+ if (logWriter != null)\r
+ {\r
+ synchronized (logWriter) {\r
+ e.printStackTrace(logWriter);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ e.printStackTrace();\r
+ }\r
+ \r
+ if (cloudscapeLogWriter != null)\r
+ {\r
+ synchronized(cloudscapeLogWriter) {\r
+ e.printStackTrace(cloudscapeLogWriter);\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+\r
+\r
+ /**\r
+ * Write a message to console output stream\r
+ *\r
+ * @param msg message\r
+ */\r
+ public void consoleMessage(String msg)\r
+ {\r
+ // print to console if we have one\r
+ if (logWriter != null)\r
+ {\r
+// //Added by Jeff HUANG\r
+// try {\r
+// Thread.sleep(1000);\r
+// } catch (InterruptedException e) {\r
+// // TODO Auto-generated catch block\r
+// e.printStackTrace();\r
+// }\r
+ \r
+ synchronized(logWriter) {\r
+ logWriter.println(msg);\r
+ }\r
+ }\r
+ // always print to derby.log\r
+ if (cloudscapeLogWriter != null)\r
+ synchronized(cloudscapeLogWriter)\r
+ {\r
+ Monitor.logMessage(msg);\r
+ }\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ * Start a network server. Launches a separate thread with \r
+ * DRDAServerStarter. Want to use Monitor.startModule,\r
+ * so it can all get shutdown when Derby shuts down, but \r
+ * can't get it working right now.\r
+ *\r
+ * @param consoleWriter PrintWriter to which server console will be \r
+ * output. Null will disable console output.\r
+ *\r
+ * \r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void start(PrintWriter consoleWriter)\r
+ throws Exception\r
+ {\r
+ DRDAServerStarter starter = new DRDAServerStarter();\r
+ starter.setStartInfo(hostAddress,portNumber,consoleWriter);\r
+ this.setLogWriter(consoleWriter);\r
+ startNetworkServer();\r
+ starter.boot(false,null);\r
+ }\r
+\r
+ /**\r
+ * Create the right kind of server socket\r
+ */\r
+ \r
+ private ServerSocket createServerSocket()\r
+ throws IOException\r
+ {\r
+ if (hostAddress == null)\r
+ hostAddress = InetAddress.getByName(hostArg);\r
+ // Make a list of valid\r
+ // InetAddresses for NetworkServerControl\r
+ // admin commands.\r
+ buildLocalAddressList(hostAddress);\r
+ \r
+ // Create the right kind of socket\r
+ switch (getSSLMode()) {\r
+ case SSL_OFF:\r
+ default:\r
+ ServerSocketFactory sf =\r
+ ServerSocketFactory.getDefault();\r
+ return sf.createServerSocket(portNumber\r
+ ,0,\r
+ hostAddress);\r
+ case SSL_BASIC:\r
+ SSLServerSocketFactory ssf =\r
+ (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();\r
+ return (SSLServerSocket)ssf.createServerSocket(portNumber,\r
+ 0,\r
+ hostAddress);\r
+ case SSL_PEER_AUTHENTICATION:\r
+ SSLServerSocketFactory ssf2 =\r
+ (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();\r
+ SSLServerSocket sss2= \r
+ (SSLServerSocket)ssf2.createServerSocket(portNumber,\r
+ 0,\r
+ hostAddress);\r
+ sss2.setNeedClientAuth(true);\r
+ return sss2;\r
+ }\r
+ }\r
+ \r
+\r
+ /**\r
+ * Start a network server\r
+ *\r
+ * @param consoleWriter PrintWriter to which server console will be \r
+ * output. Null will disable console output.\r
+ *\r
+ * \r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void blockingStart(PrintWriter consoleWriter)\r
+ throws Exception\r
+ {\r
+ startNetworkServer();\r
+ setLogWriter(consoleWriter);\r
+ cloudscapeLogWriter = Monitor.getStream().getPrintWriter();\r
+ if (SanityManager.DEBUG && debugOutput)\r
+ {\r
+ memCheck.showmem();\r
+ mc = new memCheck(200000);\r
+ mc.start();\r
+ }\r
+ // Open a server socket listener \r
+ try{\r
+ serverSocket = \r
+ (ServerSocket) \r
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {\r
+ public Object run() throws IOException\r
+ {\r
+ return createServerSocket();\r
+ }\r
+ });\r
+ } catch (PrivilegedActionException e) {\r
+ Exception e1 = e.getException();\r
+\r
+ // Test for UnknownHostException first since it's a\r
+ // subbclass of IOException (and consolePropertyMessage\r
+ // throws an exception when the severity is S (or U).\r
+ if (e1 instanceof UnknownHostException) {\r
+ consolePropertyMessage("DRDA_UnknownHost.S", hostArg);\r
+ } else if (e1 instanceof IOException) {\r
+ consolePropertyMessage("DRDA_ListenPort.S", \r
+ new String [] {\r
+ Integer.toString(portNumber), \r
+ hostArg,\r
+ // Since SocketException\r
+ // is used for a phletora\r
+ // of situations, we need\r
+ // to communicate the\r
+ // underlying exception\r
+ // string to the user.\r
+ e1.toString()}); \r
+ } else {\r
+ throw e1;\r
+ }\r
+ } catch (Exception e) {\r
+ // If we find other (unexpected) errors, we ultimately exit--so make\r
+ // sure we print the error message before doing so (Beetle 5033).\r
+ throwUnexpectedException(e);\r
+ }\r
+\r
+ switch (getSSLMode()) {\r
+ default:\r
+ case SSL_OFF:\r
+ consolePropertyMessage("DRDA_Ready.I", new String [] \r
+ {Integer.toString(portNumber), att_srvclsnm, versionString,\r
+ getFormattedTimestamp()});\r
+ break;\r
+ case SSL_BASIC:\r
+ consolePropertyMessage("DRDA_SSLReady.I", new String [] \r
+ {Integer.toString(portNumber), att_srvclsnm, versionString,\r
+ getFormattedTimestamp()});\r
+ break;\r
+ case SSL_PEER_AUTHENTICATION:\r
+ consolePropertyMessage("DRDA_SSLClientAuthReady.I", new String [] \r
+ {Integer.toString(portNumber), att_srvclsnm, versionString,\r
+ getFormattedTimestamp()});\r
+ break;\r
+ }\r
+ \r
+ // We accept clients on a separate thread so we don't run into a problem\r
+ // blocking on the accept when trying to process a shutdown\r
+ final ClientThread clientThread = \r
+ (ClientThread) AccessController.doPrivileged(\r
+ new PrivilegedExceptionAction() {\r
+ public Object run() throws Exception\r
+ {\r
+ return new ClientThread(thisControl, \r
+ serverSocket);\r
+ }\r
+ }\r
+ );\r
+ clientThread.start();//let's see what the client thread doing?\r
+ \r
+ // wait until we are told to shutdown or someone sends an InterruptedException\r
+ synchronized(shutdownSync) {\r
+ try {\r
+ shutdownSync.wait();\r
+ }\r
+ catch (InterruptedException e)\r
+ {\r
+ shutdown = true;\r
+ }\r
+ }\r
+\r
+ //oh, it takes so long a procedure to close the service\r
+ \r
+ AccessController.doPrivileged(\r
+ new PrivilegedAction() {\r
+ public Object run() {\r
+ // Need to interrupt the memcheck thread if it is sleeping.\r
+ if (mc != null)\r
+ mc.interrupt();\r
+\r
+ //interrupt client thread\r
+ clientThread.interrupt();\r
+\r
+ return null;\r
+ }\r
+ });\r
+ \r
+ // Close out the sessions\r
+ synchronized(sessionTable) {\r
+ for (Enumeration e = sessionTable.elements(); e.hasMoreElements(); )\r
+ { \r
+ Session session = (Session) e.nextElement();\r
+ session.close();\r
+ }\r
+ }\r
+\r
+ synchronized (threadList)\r
+ {\r
+ //interrupt any connection threads still active\r
+ for (int i = 0; i < threadList.size(); i++)\r
+ {\r
+ final DRDAConnThread threadi = (DRDAConnThread)threadList.get(i);\r
+ \r
+ threadi.close();\r
+ AccessController.doPrivileged(\r
+ new PrivilegedAction() {\r
+ public Object run() {\r
+ threadi.interrupt();\r
+ return null;\r
+ }\r
+ });\r
+ }\r
+ threadList.clear();\r
+ }\r
+ \r
+ \r
+\r
+ \r
+ // close the listener socket\r
+ try{\r
+ serverSocket.close();\r
+ }catch(IOException e){\r
+ consolePropertyMessage("DRDA_ListenerClose.S");\r
+ }\r
+\r
+\r
+ // Wake up those waiting on sessions, so\r
+ // they can close down\r
+ synchronized (runQueue) {\r
+ runQueue.notifyAll();\r
+ } \r
+\r
+ if (shutdownDatabasesOnShutdown) {\r
+\r
+ // Shutdown Derby\r
+ try {\r
+ if (cloudscapeDriver != null)\r
+ cloudscapeDriver.connect("jdbc:derby:;shutdown=true",\r
+ (Properties) null);\r
+ } catch (SQLException sqle) {\r
+ // If we can't shutdown Derby. Perhaps authentication is\r
+ // set to true or some other reason. We will just print a\r
+ // message to the console and proceed.\r
+ String expectedState =\r
+ StandardException.getSQLStateFromIdentifier(\r
+ SQLState.CLOUDSCAPE_SYSTEM_SHUTDOWN);\r
+ if (!expectedState.equals(sqle.getSQLState())) {\r
+ consolePropertyMessage("DRDA_ShutdownWarning.I",\r
+ sqle.getMessage());\r
+ }\r
+ }\r
+ }\r
+\r
+ consolePropertyMessage("DRDA_ShutdownSuccess.I", new String [] \r
+ {att_srvclsnm, versionString, \r
+ getFormattedTimestamp()});\r
+ \r
+\r
+ }\r
+ \r
+ /** \r
+ * Load Derby and save driver for future use.\r
+ * We can't call Driver Manager when the client connects, \r
+ * because they might be holding the DriverManager lock.\r
+ *\r
+ * \r
+ */\r
+\r
+ \r
+\r
+\r
+ protected void startNetworkServer() throws Exception\r
+ {\r
+\r
+ // we start the Derby server here.\r
+ boolean restartCheck = this.restartFlag;\r
+ synchronized (serverStartSync) {\r
+\r
+ if (restartCheck == this.restartFlag) {\r
+ // then we can go ahead and restart the server (odds\r
+ // that some else has just done so are very slim (but not\r
+ // impossible--however, even if it does happen, things\r
+ // should still work correctly, just not as efficiently...))\r
+\r
+ try {\r
+ \r
+ if (cleanupOnStart) {\r
+ // we're restarting the server (probably after a shutdown\r
+ // exception), so we need to clean up first.\r
+\r
+ // Close and remove sessions on runQueue.\r
+ synchronized (runQueue) {\r
+ for (int i = 0; i < runQueue.size(); i++) {\r
+ Session s = (Session) runQueue.get(i);\r
+ s.close();\r
+ removeFromSessionTable(s.getConnNum());\r
+ }\r
+ runQueue.clear();\r
+ }\r
+\r
+ // DERBY-1326: There could be active threads that\r
+ // contain old/invalid sessions. These sessions won't\r
+ // be cleaned up until there is some activity on\r
+ // them. We could optimize this by going through\r
+ // sessionTable and closing the sessions' socket\r
+ // streams.\r
+\r
+ // Unload driver, then restart the server.\r
+ cloudscapeDriver = null; // so it gets collected.\r
+ System.gc();\r
+ }\r
+\r
+ // start the server.\r
+ Class.forName(CLOUDSCAPE_DRIVER).newInstance();//start the embedded driver, it starts two daemon threads: derby.antiGC and Time-0\r
+ \r
+ //Added by Jeff Huang\r
+ new org.apache.derby.jdbc.EmbeddedDriver();\r
+ \r
+ cloudscapeDriver = DriverManager.getDriver(Attribute.PROTOCOL);\r
+\r
+ }\r
+ catch (Exception e) {\r
+ this.consoleExceptionPrintTrace(e);\r
+ consolePropertyMessage("DRDA_LoadException.S", e.getMessage());\r
+ }\r
+ cleanupOnStart = true;\r
+ this.restartFlag = !this.restartFlag;\r
+ }\r
+ // else, multiple threads hit this synchronize block at the same\r
+ // time, but one of them already executed it--so all others just\r
+ // return and do nothing (no need to restart the server multiple\r
+ // times in a row).\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Shutdown a network server\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void shutdown()\r
+ throws Exception\r
+ {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_SHUTDOWN);\r
+ send();\r
+ readResult();\r
+ // Wait up to 10 seconds for things to really shut down\r
+ // need a quiet ping so temporarily disable the logwriter\r
+ PrintWriter savWriter = logWriter;\r
+ // DERBY-1571: If logWriter is null, stack traces are printed to\r
+ // System.err. Set logWriter to a silent stream to suppress stack\r
+ // traces too.\r
+ FilterOutputStream silentStream = new FilterOutputStream(null) {\r
+ public void write(int b) { }\r
+ public void flush() { }\r
+ public void close() { }\r
+ };\r
+ setLogWriter(new PrintWriter(silentStream));\r
+ int ntry;\r
+ for (ntry = 0; ntry < SHUTDOWN_CHECK_ATTEMPTS; ntry++)\r
+ {\r
+ Thread.sleep(SHUTDOWN_CHECK_INTERVAL);\r
+ try {\r
+ pingWithNoOpen();\r
+ } catch (Exception e) \r
+ {\r
+ // as soon as we can't ping return\r
+ break;\r
+ }\r
+ }\r
+ closeSocket();\r
+ \r
+ \r
+ if (ntry == SHUTDOWN_CHECK_ATTEMPTS)\r
+ consolePropertyMessage("DRDA_ShutdownError.S", new String [] {\r
+ Integer.toString(portNumber), \r
+ hostArg}); \r
+ \r
+ logWriter= savWriter;\r
+ return;\r
+ }\r
+\r
+ /*\r
+ Shutdown the server directly (If you have the original object)\r
+ No Network communication needed.\r
+ */\r
+ public void directShutdown() {\r
+ shutdown = true;\r
+ synchronized(shutdownSync) { \r
+ // wake up the server thread\r
+ shutdownSync.notifyAll();\r
+ }\r
+ \r
+ }\r
+\r
+\r
+ /**\r
+ */\r
+ public boolean isServerStarted() throws Exception\r
+ {\r
+ try {\r
+ ping();\r
+ }\r
+ catch (Exception e) {\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Ping opening an new socket and close it.\r
+ * @throws Exception\r
+ */\r
+ public void ping() throws Exception\r
+ {\r
+ setUpSocket();\r
+ pingWithNoOpen();\r
+ closeSocket();\r
+ }\r
+ \r
+ /**\r
+ * Ping the server using the client socket that is already open.\r
+ */\r
+ private void pingWithNoOpen() throws Exception\r
+ {\r
+ \r
+ // database no longer used, but don't change the protocol \r
+ // in case we add\r
+ // authorization later.\r
+ String database = null; // no longer used but don't change the protocol\r
+ String user = null;\r
+ String password = null;\r
+\r
+ \r
+ writeCommandHeader(COMMAND_TESTCONNECTION);\r
+ writeLDString(database);\r
+ writeLDString(user);\r
+ writeLDString(password);\r
+ send();\r
+ readResult();\r
+ }\r
+\r
+\r
+ /**\r
+ * Turn tracing on or off for all sessions\r
+ *\r
+ * @param on true to turn tracing on, false to turn tracing off\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void trace(boolean on)\r
+ throws Exception\r
+ {\r
+ trace(0, on);\r
+ }\r
+\r
+ /**\r
+ * Turn tracing on or off for one session or all sessions\r
+ *\r
+ * @param connNum the connNum of the session, 0 if all sessions\r
+ * @param on true to turn tracing on, false to turn tracing off\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void trace(int connNum, boolean on)\r
+ throws Exception\r
+ {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_TRACE);\r
+ commandOs.writeInt(connNum);\r
+ writeByte(on ? 1 : 0);\r
+ send();\r
+ readResult();\r
+ consoleTraceMessage(connNum, on);\r
+ closeSocket();\r
+ }\r
+\r
+ /**\r
+ * Print trace change message to console\r
+ *\r
+ * @param on true to print tracing on, false to print tracing off\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void consoleTraceMessage(int connNum, boolean on)\r
+ throws Exception\r
+ {\r
+ if (connNum == 0)\r
+ consolePropertyMessage("DRDA_TraceChangeAll.I", on ? "DRDA_ON.I" : "DRDA_OFF.I");\r
+ else\r
+ {\r
+ String[] args = new String[2];\r
+ args[0] = on ? "DRDA_ON.I" : "DRDA_OFF.I";\r
+ args[1] = new Integer(connNum).toString();\r
+ consolePropertyMessage("DRDA_TraceChangeOne.I", args);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Turn logging connections on or off. When logging is turned on a message is\r
+ * written to derby.log each time a connection is made.\r
+ *\r
+ * @param on true to turn on, false to turn off\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void logConnections(boolean on)\r
+ throws Exception\r
+ {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_LOGCONNECTIONS);\r
+ writeByte(on ? 1 : 0);\r
+ send();\r
+ readResult();\r
+ closeSocket();\r
+ }\r
+\r
+ /**\r
+ *@see NetworkServerControl#setTraceDirectory\r
+ */\r
+ public void sendSetTraceDirectory(String traceDirectory)\r
+ throws Exception\r
+ {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_TRACEDIRECTORY);\r
+ writeLDString(traceDirectory);\r
+ send();\r
+ readResult();\r
+ closeSocket();\r
+ }\r
+\r
+ /**\r
+ *@see NetworkServerControl#getSysinfo\r
+ */\r
+ public String sysinfo()\r
+ throws Exception\r
+ {\r
+ try {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_SYSINFO);\r
+ send();\r
+ return readStringReply("DRDA_SysInfoError.S");\r
+ } finally {\r
+ closeSocket();\r
+ }\r
+ }\r
+\r
+ /**\r
+ *@see NetworkServerControl#getRuntimeInfo\r
+ */\r
+ public String runtimeInfo()\r
+ throws Exception \r
+ {\r
+ try {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_RUNTIME_INFO);\r
+ send();\r
+ return readStringReply("DRDA_RuntimeInfoError.S");\r
+ } finally {\r
+ closeSocket();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Display usage information\r
+ *\r
+ */\r
+ public void usage()\r
+ {\r
+ try {\r
+ for (int i = 1; i <= NO_USAGE_MSGS; i++)\r
+ consolePropertyMessage("DRDA_Usage"+i+".I");\r
+ } catch (Exception e) {} // ignore exceptions - there shouldn't be any\r
+ }\r
+\r
+ /**\r
+ * Connect to network server and set connection maxthread parameter\r
+ *\r
+ * @param max maximum number of connections, if 0, connections \r
+ * created when no free connection available\r
+ * if -1, use default\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void netSetMaxThreads(int max) throws Exception\r
+ {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_MAXTHREADS);\r
+ commandOs.writeInt(max);\r
+ send();\r
+ readResult();\r
+ int newval = readInt();\r
+ consolePropertyMessage("DRDA_MaxThreadsChange.I", \r
+ new Integer(newval).toString());\r
+ closeSocket();\r
+ }\r
+\r
+ /**\r
+ * Set network server connection timeslice parameter\r
+ *\r
+ * @param timeslice amount of time given to each session before yielding to \r
+ * another session, if 0, never yield. if -1, use default.\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public void netSetTimeSlice(int timeslice)\r
+ throws Exception\r
+ {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_TIMESLICE);\r
+ commandOs.writeInt(timeslice);\r
+ send();\r
+ readResult();\r
+ int newval = readInt();\r
+ consolePropertyMessage("DRDA_TimeSliceChange.I", \r
+ new Integer(newval).toString());\r
+ closeSocket();\r
+ }\r
+\r
+ /**\r
+ * Get current properties\r
+ *\r
+ * @return Properties object containing properties\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ public Properties getCurrentProperties() \r
+ throws Exception\r
+ {\r
+ setUpSocket();\r
+ writeCommandHeader(COMMAND_PROPERTIES);\r
+ send();\r
+ byte [] val = readBytesReply("DRDA_PropertyError.S");\r
+ closeSocket();\r
+ Properties p = new Properties();\r
+ try {\r
+ ByteArrayInputStream bs = new ByteArrayInputStream(val);\r
+ p.load(bs);\r
+ } catch (IOException io) {\r
+ consolePropertyMessage("DRDA_IOException.S", \r
+ io.getMessage());\r
+ }\r
+ return p;\r
+ }\r
+\r
+ /**\r
+ * Set a thread name to be something that is both meaningful and unique (primarily\r
+ * for debugging purposes).\r
+ *\r
+ * The received thread's name is set to a new string of the form\r
+ * [newName + "_n"], where 'n' is a unique thread id originally generated\r
+ * by the jvm Thread constructor. If the default name of the thread has\r
+ * been changed before getting here, then nothing is done.\r
+ *\r
+ * @param thrd An instance of a Thread object that still has its default\r
+ * thread name (as generated by the jvm Thread constructor). This should\r
+ * always be of the form "Thread-N", where N is a unique thread id\r
+ * generated by the jvm. Ex. "Thread-0", "Thread-1", etc.\r
+ *\r
+ **/\r
+ public static void setUniqueThreadName(Thread thrd, String newName) {\r
+\r
+ // First, pull off the unique thread id already found in thrd's default name;\r
+ // we do so by searching for the '-' character, and then counting everything\r
+ // after it as a N.\r
+ if (thrd.getName().indexOf("Thread-") == -1) {\r
+ // default name has been changed; don't do anything.\r
+ return;\r
+ }\r
+ else {\r
+ String oldName = thrd.getName();\r
+ thrd.setName(newName + "_" +\r
+ oldName.substring(oldName.indexOf("-")+1, oldName.length()));\r
+ } // end else.\r
+\r
+ return;\r
+\r
+ }\r
+\r
+ /*******************************************************************************/\r
+ /* Protected methods */\r
+ /*******************************************************************************/\r
+ /**\r
+ * Remove session from session table\r
+ *\r
+ * @param sessionid id of session to be removed\r
+ */\r
+ protected void removeFromSessionTable(int sessionid)\r
+ {\r
+ sessionTable.remove(new Integer(sessionid));\r
+ }\r
+\r
+ /**\r
+ * processCommands reads and processes NetworkServerControlImpl commands sent\r
+ * to the network server over the socket. The protocol used is\r
+ * 4 bytes - String CMD:\r
+ * 2 bytes - Protocol version\r
+ * 1 byte - length of locale (0 for default)\r
+ * n bytes - locale\r
+ * 1 byte - length of codeset (0 for default)\r
+ * n bytes - codeset\r
+ * 1 byte - command\r
+ * n bytes - parameters for the command\r
+ * The server returns\r
+ * 4 bytes - String RPY:\r
+ * for most commands\r
+ * 1 byte - command result, 0 - OK, 1 - warning, 2 - error\r
+ * if warning or error\r
+ * 1 bytes - length of message key\r
+ * n bytes - message key\r
+ * 1 byte - number of parameters to message\r
+ * {2 bytes - length of parameter\r
+ * n bytes - parameter} for each parameter\r
+ * for sysinfo\r
+ * 1 byte - command result, 0 - OK, 1 - warning, 2 - error\r
+ * if OK \r
+ * 2 bytes - length of sysinfo\r
+ * n bytes - sysinfo\r
+ * \r
+ * \r
+ * Note, the 3rd byte of the command must not be 'D0' to distinquish it \r
+ * from DSS structures.\r
+ * The protocol for the parameters for each command follows:\r
+ *\r
+ * Command: trace <connection id> {on | off}\r
+ * Protocol:\r
+ * 4 bytes - connection id - connection id of 0 means all sessions\r
+ * 1 byte - 0 off, 1 on\r
+ * \r
+ * Command: logConnections {on | off}\r
+ * Protocol:\r
+ * 1 byte - 0 off, 1 on\r
+ * \r
+ * Command: shutdown\r
+ * No parameters\r
+ * \r
+ * Command: sysinfo\r
+ * No parameters\r
+ * \r
+ * Command: dbstart\r
+ * Protocol:\r
+ * 2 bytes - length of database name\r
+ * n bytes - database name\r
+ * 2 bytes - length of boot password\r
+ * n bytes - boot password \r
+ * 2 bytes - length of encryption algorithm\r
+ * n bytes - encryption algorithm\r
+ * 2 bytes - length of encryption provider\r
+ * n bytes - encryption provider\r
+ * 2 bytes - length of user name\r
+ * n bytes - user name\r
+ * 2 bytes - length of password\r
+ * n bytes - password\r
+ *\r
+ * Command: dbshutdown\r
+ * Protocol:\r
+ * 2 bytes - length of database name\r
+ * n bytes - database name\r
+ * 2 bytes - length of user name\r
+ * n bytes - user name\r
+ * 2 bytes - length of password\r
+ * n bytes - password\r
+ *\r
+ * Command: connpool\r
+ * Protocol:\r
+ * 2 bytes - length of database name, if 0, default for all databases\r
+ * is set\r
+ * n bytes - database name\r
+ * 2 bytes - minimum number of connections, if 0, connection pool not used\r
+ * if value is -1 use default\r
+ * 2 bytes - maximum number of connections, if 0, connections are created\r
+ * as needed, if value is -1 use default\r
+ *\r
+ * Command: maxthreads\r
+ * Protocol:\r
+ * 2 bytes - maximum number of threads\r
+ *\r
+ * Command: timeslice \r
+ * Protocol:\r
+ * 4 bytes - timeslice value\r
+ *\r
+ * Command: tracedirectory\r
+ * Protocol:\r
+ * 2 bytes - length of directory name\r
+ * n bytes - directory name\r
+ *\r
+ * Command: test connection\r
+ * Protocol:\r
+ * 2 bytes - length of database name if 0, just the connection\r
+ * to the network server is tested and user name and \r
+ * password aren't sent\r
+ * n bytes - database name\r
+ * 2 bytes - length of user name (optional)\r
+ * n bytes - user name\r
+ * 2 bytes - length of password (optional)\r
+ * n bytes - password\r
+ *\r
+ * The calling routine is synchronized so that multiple threads don't clobber each\r
+ * other. This means that configuration commands will be serialized.\r
+ * This shouldn't be a problem since they should be fairly rare.\r
+ * \r
+ * @param reader input reader for command\r
+ * @param writer output writer for command\r
+ * @param session session information\r
+ *\r
+ * @exception Throwable throws an exception if an error occurs\r
+ */\r
+ protected synchronized void processCommands(DDMReader reader, DDMWriter writer, \r
+ Session session) throws Throwable\r
+ {\r
+ try {\r
+ String protocolStr = reader.readCmdString(4);\r
+ String locale = DEFAULT_LOCALE;\r
+ String codeset = null;\r
+ // get the version\r
+ int version = reader.readNetworkShort();\r
+ if (version <= 0 || version > PROTOCOL_VERSION)\r
+ throw new Throwable(langUtil.getTextMessage("DRDA_UnknownProtocol.S", new Integer(version).toString()));\r
+ int localeLen = reader.readByte();\r
+ if (localeLen > 0)\r
+ {\r
+ currentSession = session;\r
+ locale = reader.readCmdString(localeLen);\r
+ session.langUtil = new LocalizedResource(codeset,locale,DRDA_PROP_MESSAGES);\r
+ }\r
+ String notLocalMessage = null;\r
+ // for now codesetLen is always 0\r
+ int codesetLen = reader.readByte();\r
+ int command = reader.readByte();\r
+ if (command != COMMAND_TESTCONNECTION)\r
+ {\r
+ try {\r
+ checkAddressIsLocal(session.clientSocket.getInetAddress());\r
+ }catch (Exception e)\r
+ {\r
+ notLocalMessage = e.getMessage();\r
+ }\r
+ }\r
+ if (notLocalMessage != null)\r
+ {\r
+ sendMessage(writer, ERROR,notLocalMessage);\r
+ session.langUtil = null;\r
+ currentSession = null;\r
+ return;\r
+ }\r
+\r
+ switch(command)\r
+ {\r
+ case COMMAND_SHUTDOWN:\r
+ sendOK(writer);\r
+ directShutdown();\r
+ break;\r
+ case COMMAND_TRACE:\r
+ sessionArg = reader.readNetworkInt();\r
+ boolean on = (reader.readByte() == 1);\r
+ if (setTrace(on))\r
+ {\r
+ sendOK(writer);\r
+ }\r
+ else\r
+ {\r
+ if (sessionArg != 0)\r
+ sendMessage(writer, ERROR, \r
+ localizeMessage("DRDA_SessionNotFound.U", \r
+ (session.langUtil == null) ? langUtil : session.langUtil,\r
+ new String [] {new Integer(sessionArg).toString()}));\r
+ else\r
+ sendMessage(writer, ERROR, \r
+ localizeMessage("DRDA_ErrorStartingTracing.S",null)); \r
+ }\r
+ break;\r
+ case COMMAND_TRACEDIRECTORY:\r
+ setTraceDirectory(reader.readCmdString());\r
+ sendOK(writer);\r
+ consolePropertyMessage("DRDA_TraceDirectoryChange.I", traceDirectory);\r
+ break;\r
+ case COMMAND_TESTCONNECTION:\r
+ databaseArg = reader.readCmdString();\r
+ userArg = reader.readCmdString();\r
+ passwordArg = reader.readCmdString();\r
+ if (databaseArg != null)\r
+ connectToDatabase(writer, databaseArg, userArg, passwordArg);\r
+ else\r
+ sendOK(writer);\r
+ break;\r
+ case COMMAND_LOGCONNECTIONS:\r
+ boolean log = (reader.readByte() == 1);\r
+ setLogConnections(log);\r
+ sendOK(writer);\r
+ consolePropertyMessage("DRDA_LogConnectionsChange.I",\r
+ (log ? "DRDA_ON.I" : "DRDA_OFF.I"));\r
+ break;\r
+ case COMMAND_SYSINFO:\r
+ sendSysInfo(writer);\r
+ break;\r
+ case COMMAND_PROPERTIES:\r
+ sendPropInfo(writer);\r
+ break;\r
+ case COMMAND_RUNTIME_INFO:\r
+ sendRuntimeInfo(writer);\r
+ break;\r
+ case COMMAND_MAXTHREADS:\r
+ int max = reader.readNetworkInt();\r
+ try {\r
+ setMaxThreads(max);\r
+ }catch (Exception e) {\r
+ sendMessage(writer, ERROR, e.getMessage());\r
+ return;\r
+ }\r
+ int newval = getMaxThreads();\r
+ sendOKInt(writer, newval);\r
+ consolePropertyMessage("DRDA_MaxThreadsChange.I", \r
+ new Integer(newval).toString());\r
+ break;\r
+ case COMMAND_TIMESLICE:\r
+ int timeslice = reader.readNetworkInt();\r
+ try {\r
+ setTimeSlice(timeslice);\r
+ }catch (Exception e) {\r
+ sendMessage(writer, ERROR, e.getMessage());\r
+ return;\r
+ }\r
+ newval = getTimeSlice();\r
+ sendOKInt(writer, newval);\r
+ consolePropertyMessage("DRDA_TimeSliceChange.I", \r
+ new Integer(newval).toString());\r
+ break;\r
+ }\r
+ } catch (DRDAProtocolException e) {\r
+ //we need to handle this since we aren't in DRDA land here\r
+ consoleExceptionPrintTrace(e);\r
+\r
+ } catch (Exception e) {\r
+ consoleExceptionPrintTrace(e);\r
+ }\r
+ finally {\r
+ session.langUtil = null;\r
+ currentSession = null;\r
+ }\r
+ }\r
+ /**\r
+ * Get the next session for the thread to work on\r
+ * Called from DRDAConnThread after session completes or timeslice\r
+ * exceeded. \r
+ *\r
+ * If there is a waiting session, pick it up and put currentSession \r
+ * at the back of the queue if there is one.\r
+ * @param currentSession session thread is currently working on\r
+ *\r
+ * @return next session to work on, could be same as current session\r
+ */\r
+ protected Session getNextSession(Session currentSession)\r
+ {\r
+ Session retval = null;\r
+ if (shutdown == true)\r
+ return retval;\r
+ synchronized (runQueue)\r
+ {\r
+ try {\r
+ // nobody waiting - go on with current session\r
+ if (runQueue.size() == 0)\r
+ {\r
+ // no current session - wait for some work\r
+ if (currentSession == null)\r
+ {\r
+ while (runQueue.size() == 0)\r
+ {\r
+ // This thread has nothing to do now so \r
+ // we will add it to freeThreads\r
+ freeThreads++;\r
+ runQueue.wait();\r
+ if (shutdown == true)\r
+ return null;\r
+ freeThreads--;\r
+ }\r
+ }\r
+ else\r
+ return currentSession;\r
+ }\r
+ retval = (Session) runQueue.elementAt(0);\r
+ runQueue.removeElementAt(0);\r
+ if (currentSession != null)\r
+ runQueueAdd(currentSession);\r
+ } catch (InterruptedException e) {\r
+ // If for whatever reason (ex. database shutdown) a waiting thread is\r
+ // interrupted while in this method, that thread is going to be\r
+ // closed down, so we need to decrement the number of threads\r
+ // that will be available for use.\r
+ freeThreads--;\r
+ }\r
+ }\r
+ return retval;\r
+ }\r
+ /**\r
+ * Get the stored application requester or store if we haven't seen it yet\r
+ *\r
+ * @param appRequester Application Requester to look for\r
+ *\r
+ * @return stored application requester\r
+ */\r
+ protected AppRequester getAppRequester(AppRequester appRequester)\r
+ {\r
+ AppRequester s = null;\r
+\r
+ if (SanityManager.DEBUG) {\r
+ if (appRequester == null)\r
+ SanityManager.THROWASSERT("null appRequester in getAppRequester");\r
+ }\r
+\r
+ if (!appRequesterTable.isEmpty())\r
+ s = (AppRequester)appRequesterTable.get(appRequester.prdid);\r
+\r
+ if (s == null)\r
+ {\r
+ appRequesterTable.put(appRequester.prdid, appRequester);\r
+ return appRequester;\r
+ }\r
+ else\r
+ {\r
+ //compare just in case there are some differences\r
+ //if they are different use the one we just read in\r
+ if (s.equals(appRequester))\r
+ return s;\r
+ else\r
+ return appRequester;\r
+ }\r
+ }\r
+ /**\r
+ * Get the server manager level for a given manager\r
+ *\r
+ * @param manager codepoint for manager\r
+ * @return manager level\r
+ */\r
+ protected int getManagerLevel(int manager)\r
+ {\r
+ int mindex = CodePoint.getManagerIndex(manager);\r
+ if (SanityManager.DEBUG) {\r
+ if (mindex == CodePoint.UNKNOWN_MANAGER)\r
+ SanityManager.THROWASSERT("manager out of bounds");\r
+ }\r
+ return MGR_LEVELS[mindex];\r
+ }\r
+ /**\r
+ * Check whether a CCSID code page is supported\r
+ *\r
+ * @param ccsid CCSID to check\r
+ * @return true if supported; false otherwise\r
+ */\r
+ protected boolean supportsCCSID(int ccsid)\r
+ {\r
+ try {\r
+ CharacterEncodings.getJavaEncoding(ccsid);\r
+ }\r
+ catch (Exception e) {\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+ /**\r
+ * Put property message on console\r
+ *\r
+ * @param msgProp message property key\r
+ *\r
+ * @throws Exception if an error occurs\r
+ */\r
+ protected void consolePropertyMessage(String msgProp)\r
+ throws Exception\r
+ {\r
+ consolePropertyMessageWork(msgProp, null);\r
+ }\r
+ /**\r
+ * Put property message on console\r
+ *\r
+ * @param msgProp message property key\r
+ * @param arg argument for message\r
+ *\r
+ * @throws Exception if an error occurs\r
+ */\r
+ protected void consolePropertyMessage(String msgProp, String arg)\r
+ throws Exception\r
+ {\r
+ consolePropertyMessageWork(msgProp, new String [] {arg});\r
+ }\r
+ /**\r
+ * Put property message on console\r
+ *\r
+ * @param msgProp message property key\r
+ * @param args argument array for message\r
+ *\r
+ * @throws Exception if an error occurs\r
+ */\r
+ protected void consolePropertyMessage(String msgProp, String [] args)\r
+ throws Exception\r
+ {\r
+ consolePropertyMessageWork(msgProp, args);\r
+ }\r
+ /**\r
+ * Is this the command protocol\r
+ * \r
+ * @param val\r
+ */\r
+ protected static boolean isCmd(String val)\r
+ {\r
+ if (val.equals(COMMAND_HEADER))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+\r
+ /*******************************************************************************/\r
+ /* Private methods */\r
+ /*******************************************************************************/\r
+ /**\r
+ * Write Command reply\r
+ *\r
+ * @param writer writer to use \r
+ *\r
+ * @throws Exception if a problem occurs sending OK\r
+ */\r
+ private void writeCommandReplyHeader(DDMWriter writer) throws Exception\r
+ {\r
+ writer.setCMDProtocol();\r
+ writer.writeString(REPLY_HEADER);\r
+ }\r
+ \r
+ /**\r
+ * Send OK from server to client after processing a command\r
+ *\r
+ * @param writer writer to use for sending OK\r
+ *\r
+ * @throws Exception if a problem occurs sending OK\r
+ */\r
+ private void sendOK(DDMWriter writer) throws Exception\r
+ {\r
+ writeCommandReplyHeader(writer);\r
+ writer.writeByte(OK);\r
+ writer.flush();\r
+ }\r
+ /**\r
+ * Send OK and int value\r
+ *\r
+ * @param writer writer to use for sending\r
+ * @param val int val to send\r
+ * \r
+ * @throws Exception if a problem occurs\r
+ */\r
+ private void sendOKInt(DDMWriter writer, int val) throws Exception\r
+ {\r
+ writeCommandReplyHeader(writer);\r
+ writer.writeByte(OK);\r
+ writer.writeNetworkInt(val);\r
+ writer.flush();\r
+ }\r
+ /**\r
+ * Send Error or Warning from server to client after processing a command\r
+ *\r
+ * @param writer writer to use for sending message\r
+ * @param messageType 1 for Warning, 2 for Error 3 for SQLError\r
+ * @param message message \r
+ *\r
+ * @throws Exception if a problem occurs sending message\r
+ */\r
+ private void sendMessage(DDMWriter writer, int messageType, String message) \r
+ throws Exception\r
+ {\r
+ writeCommandReplyHeader(writer);\r
+ writer.writeByte(messageType);\r
+ writer.writeLDString(message);\r
+ writer.flush();\r
+ }\r
+ /**\r
+ * Send SQL Exception from server to client after processing a command\r
+ *\r
+ * @param writer writer to use for sending message\r
+ * @param se Derby exception\r
+ * @param type type of exception, SQLERROR or SQLWARNING\r
+ *\r
+ * @throws Exception if a problem occurs sending message\r
+ */\r
+ private void sendSQLMessage(DDMWriter writer, SQLException se, int type)\r
+ throws Exception\r
+ {\r
+ StringBuffer locMsg = new StringBuffer();\r
+ //localize message if necessary\r
+ while (se != null)\r
+ {\r
+ if (currentSession != null && currentSession.langUtil != null &&\r
+ se instanceof EmbedSQLException)\r
+ {\r
+ locMsg.append(se.getSQLState()+":"+ \r
+ MessageService.getLocalizedMessage(\r
+ currentSession.langUtil.getLocale(), ((EmbedSQLException)se).getMessageId(), \r
+ ((EmbedSQLException)se).getArguments()));\r
+ }\r
+ else\r
+ locMsg.append(se.getSQLState()+":"+se.getMessage());\r
+ se = se.getNextException();\r
+ if (se != null)\r
+ locMsg.append("\n");\r
+ }\r
+ sendMessage(writer, type, locMsg.toString());\r
+ }\r
+ /**\r
+ * Send SysInfo information from server to client\r
+ *\r
+ * @param writer writer to use for sending sysinfo\r
+ *\r
+ * @throws Exception if a problem occurs sending value\r
+ */\r
+ private void sendSysInfo(DDMWriter writer) throws Exception\r
+ {\r
+ StringBuffer sysinfo = new StringBuffer();\r
+ sysinfo.append(getNetSysInfo());\r
+ sysinfo.append(getCLSSysInfo());\r
+ try {\r
+ writeCommandReplyHeader(writer);\r
+ writer.writeByte(0); //O.K.\r
+ writer.writeLDString(sysinfo.toString());\r
+ } catch (DRDAProtocolException e) {\r
+ consolePropertyMessage("DRDA_SysInfoWriteError.S", e.getMessage());\r
+ }\r
+ writer.flush();\r
+ }\r
+ \r
+ /**\r
+ * Send RuntimeInfo information from server to client\r
+ *\r
+ * @param writer writer to use for sending sysinfo\r
+ *\r
+ * @throws Exception if a problem occurs sending value\r
+ */\r
+ private void sendRuntimeInfo(DDMWriter writer) throws Exception\r
+ {\r
+ try {\r
+ writeCommandReplyHeader(writer);\r
+ writer.writeByte(0); //O.K.\r
+ writer.writeLDString(getRuntimeInfo());\r
+ } catch (DRDAProtocolException e) {\r
+ consolePropertyMessage("DRDA_SysInfoWriteError.S", e.getMessage());\r
+ }\r
+ writer.flush();\r
+ }\r
+\r
+ \r
+\r
+ /**\r
+ * Send property information from server to client\r
+ *\r
+ * @param writer writer to use for sending sysinfo\r
+ *\r
+ * @throws Exception if a problem occurs sending value\r
+ */\r
+ private void sendPropInfo(DDMWriter writer) throws Exception\r
+ {\r
+ try {\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ Properties p = getPropertyValues();\r
+ p.store(out, "NetworkServerControl properties");\r
+ try {\r
+ writeCommandReplyHeader(writer);\r
+ writer.writeByte(0); //O.K.\r
+ writer.writeLDBytes(out.toByteArray());\r
+ } catch (DRDAProtocolException e) {\r
+ consolePropertyMessage("DRDA_PropInfoWriteError.S", e.getMessage());\r
+ }\r
+ writer.flush();\r
+ } \r
+ catch (Exception e) {\r
+ consoleExceptionPrintTrace(e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get Net Server information\r
+ *\r
+ * @return system information for the Network Server\r
+ */\r
+ private String getNetSysInfo() \r
+ {\r
+ StringBuffer sysinfo = new StringBuffer();\r
+ LocalizedResource localLangUtil = langUtil;\r
+ if (currentSession != null && currentSession.langUtil != null)\r
+ localLangUtil = currentSession.langUtil;\r
+ sysinfo.append(localLangUtil.getTextMessage("DRDA_SysInfoBanner.I")+ "\n");\r
+ sysinfo.append(localLangUtil.getTextMessage("DRDA_SysInfoVersion.I")+ " " + att_srvrlslv);\r
+ sysinfo.append(" ");\r
+ sysinfo.append(localLangUtil.getTextMessage("DRDA_SysInfoBuild.I")+ " " + buildNumber);\r
+ sysinfo.append(" ");\r
+ sysinfo.append(localLangUtil.getTextMessage("DRDA_SysInfoDrdaPRDID.I")+ " " + prdId);\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ sysinfo.append(" ** SANE BUILD **");\r
+ }\r
+ sysinfo.append("\n");\r
+ // add property information\r
+ Properties p = getPropertyValues();\r
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
+ PrintStream ps = new PrintStream(bos);\r
+ p.list(ps);\r
+ sysinfo.append(bos.toString());\r
+ return sysinfo.toString();\r
+ }\r
+\r
+ /**\r
+ * @see NetworkServerControl#getRuntimeInfo\r
+ */\r
+ private String getRuntimeInfo() \r
+ {\r
+ return buildRuntimeInfo(langUtil);\r
+ }\r
+\r
+ /**\r
+ * Get Derby information\r
+ *\r
+ * @return system information for Derby\r
+ *\r
+ * @throws IOException if a problem occurs encoding string\r
+ */\r
+ private String getCLSSysInfo() throws IOException\r
+ {\r
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();\r
+ LocalizedResource localLangUtil = langUtil;\r
+ if (currentSession != null && currentSession.langUtil != null)\r
+ localLangUtil = currentSession.langUtil;\r
+ LocalizedOutput aw = localLangUtil.getNewOutput(bos);\r
+ org.apache.derby.impl.tools.sysinfo.Main.getMainInfo(aw, false);\r
+ return bos.toString();\r
+ }\r
+\r
+\r
+ /**\r
+ * Parse the command-line arguments. As a side-effect, fills in various instance\r
+ * fields. This method was carved out of executeWork() so that\r
+ * NetworkServerControl can figure out whether to install a security manager\r
+ * before the server actually comes up. This is part of the work for DERBY-2196.\r
+ *\r
+ * @param args array of arguments indicating command to be executed\r
+ *\r
+ * @return the command to be executed\r
+ */\r
+ public int parseArgs(String args[]) throws Exception\r
+ {\r
+ // For convenience just use NetworkServerControlImpls log writer for user messages\r
+ logWriter = makePrintWriter(System.out);\r
+\r
+ int command = COMMAND_START; \r
+ if (args.length > 0)\r
+ command = findCommand(args);\r
+ else\r
+ {\r
+ consolePropertyMessage("DRDA_NoArgs.U");\r
+ }\r
+\r
+ return command;\r
+ }\r
+\r
+ /**\r
+ * Execute the command given on the command line\r
+ *\r
+ * @param command The command to execute. The command itself was determined by an earlier call to parseArgs().\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ * see class comments for more information\r
+ */\r
+ public void executeWork(int command) throws Exception\r
+ {\r
+ // if we didn't have a valid command just return - error already generated\r
+ if (command == COMMAND_UNKNOWN)\r
+ return;\r
+\r
+ // check that we have the right number of required arguments\r
+ if (commandArgs.size() != COMMAND_ARGS[command])\r
+ consolePropertyMessage("DRDA_InvalidNoArgs.U", COMMANDS[command]);\r
+ int min;\r
+ int max;\r
+\r
+\r
+ switch (command)\r
+ {\r
+ case COMMAND_START:\r
+ // the server was started from the command line, shutdown the\r
+ // databases when the server is shutdown\r
+ shutdownDatabasesOnShutdown = true;\r
+ blockingStart(makePrintWriter(System.out));\r
+ break;\r
+ case COMMAND_SHUTDOWN:\r
+ shutdown();\r
+ consolePropertyMessage("DRDA_ShutdownSuccess.I", new String [] \r
+ {att_srvclsnm, versionString, \r
+ getFormattedTimestamp()});\r
+ break;\r
+ case COMMAND_TRACE:\r
+ {\r
+ boolean on = isOn((String)commandArgs.elementAt(0));\r
+ trace(sessionArg, on);\r
+ consoleTraceMessage(sessionArg, on);\r
+ break;\r
+ }\r
+ case COMMAND_TRACEDIRECTORY:\r
+ setTraceDirectory((String) commandArgs.elementAt(0));\r
+ consolePropertyMessage("DRDA_TraceDirectoryChange.I", traceDirectory);\r
+ break;\r
+ case COMMAND_TESTCONNECTION:\r
+ ping();\r
+ consolePropertyMessage("DRDA_ConnectionTested.I", new String [] \r
+ {hostArg, (new Integer(portNumber)).toString()});\r
+ break;\r
+ case COMMAND_LOGCONNECTIONS:\r
+ {\r
+ boolean on = isOn((String)commandArgs.elementAt(0));\r
+ logConnections(on);\r
+ consolePropertyMessage("DRDA_LogConnectionsChange.I", on ? "DRDA_ON.I" : "DRDA_OFF.I");\r
+ break;\r
+ }\r
+ case COMMAND_SYSINFO:\r
+ {\r
+ String info = sysinfo();\r
+ consoleMessage(info);\r
+ break;\r
+ }\r
+ case COMMAND_MAXTHREADS:\r
+ max = 0;\r
+ try{\r
+ max = Integer.parseInt((String)commandArgs.elementAt(0));\r
+ }catch(NumberFormatException e){\r
+ consolePropertyMessage("DRDA_InvalidValue.U", new String [] \r
+ {(String)commandArgs.elementAt(0), "maxthreads"});\r
+ }\r
+ if (max < MIN_MAXTHREADS)\r
+ consolePropertyMessage("DRDA_InvalidValue.U", new String [] \r
+ {new Integer(max).toString(), "maxthreads"});\r
+ netSetMaxThreads(max);\r
+\r
+ break;\r
+ case COMMAND_RUNTIME_INFO:\r
+ String reply = runtimeInfo();\r
+ consoleMessage(reply);\r
+ break;\r
+ case COMMAND_TIMESLICE:\r
+ int timeslice = 0;\r
+ String timeSliceArg = (String)commandArgs.elementAt(0);\r
+ try{\r
+ timeslice = Integer.parseInt(timeSliceArg);\r
+ }catch(NumberFormatException e){\r
+ consolePropertyMessage("DRDA_InvalidValue.U", new String [] \r
+ {(String)commandArgs.elementAt(0), "timeslice"});\r
+ }\r
+ if (timeslice < MIN_TIMESLICE)\r
+ consolePropertyMessage("DRDA_InvalidValue.U", new String [] \r
+ {new Integer(timeslice).toString(), "timeslice"});\r
+ netSetTimeSlice(timeslice);\r
+ \r
+ break;\r
+ default:\r
+ //shouldn't get here\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT("Invalid command in switch:"+ command);\r
+ }\r
+ }\r
+\r
+ \r
+ /**\r
+ * Add session to the run queue\r
+ *\r
+ * @param clientSession session needing work\r
+ */\r
+ private void runQueueAdd(Session clientSession)\r
+ {\r
+ synchronized(runQueue)\r
+ {\r
+ runQueue.addElement(clientSession);\r
+ runQueue.notify();\r
+ }\r
+ }\r
+ /**\r
+ * Go through the arguments and find the command and save the dash arguments\r
+ * and arguments to the command. Only one command is allowed in the argument\r
+ * list.\r
+ *\r
+ * @param args arguments to search\r
+ *\r
+ * @return command\r
+ */\r
+ private int findCommand(String [] args) throws Exception\r
+ {\r
+ try {\r
+ // process the dashArgs and pull out the command args \r
+ int i = 0;\r
+ int newpos = 0;\r
+ while (i < args.length)\r
+ {\r
+ if (args[i].startsWith("-"))\r
+ {\r
+ newpos = processDashArg(i, args);\r
+ if (newpos == i)\r
+ commandArgs.addElement(args[i++]);\r
+ else\r
+ i = newpos;\r
+ }\r
+ else\r
+ commandArgs.addElement(args[i++]);\r
+ }\r
+ \r
+ // look up command\r
+ if (commandArgs.size() > 0)\r
+ {\r
+ for (i = 0; i < COMMANDS.length; i++)\r
+ {\r
+ if (StringUtil.SQLEqualsIgnoreCase(COMMANDS[i], \r
+ (String)commandArgs.firstElement()))\r
+ {\r
+ commandArgs.removeElementAt(0);\r
+ return i;\r
+ }\r
+ }\r
+ }\r
+ // didn't find command\r
+ consolePropertyMessage("DRDA_UnknownCommand.U", \r
+ (String) commandArgs.firstElement());\r
+ } catch (Exception e) {\r
+ if (e.getMessage().equals(NetworkServerControlImpl.UNEXPECTED_ERR))\r
+ throw e;\r
+ //Ignore expected exceptions, they will have been\r
+ //handled by the consolePropertyMessage routine\r
+ }\r
+ return COMMAND_UNKNOWN;\r
+ }\r
+ /**\r
+ * Get the dash argument. Optional arguments are formated as -x value.\r
+ *\r
+ * @param pos starting point\r
+ * @param args arguments to search\r
+ *\r
+ * @return command\r
+ *\r
+ * @exception Exception thrown if an error occurs\r
+ */\r
+ private int processDashArg(int pos, String[] args)\r
+ throws Exception\r
+ {\r
+ //check for a negative number\r
+ char c = args[pos].charAt(1);\r
+ if (c >= '0' && c <= '9')\r
+ return pos;\r
+ int dashArg = -1;\r
+ for (int i = 0; i < DASHARGS.length; i++)\r
+ {\r
+ if (DASHARGS[i].equals(args[pos].substring(1)))\r
+ {\r
+ dashArg = i;\r
+ if ( dashArg != DASHARG_UNSECURE ) { pos++ ; }\r
+ break;\r
+ }\r
+ }\r
+ if (dashArg == -1)\r
+ consolePropertyMessage("DRDA_UnknownArgument.U", args[pos]);\r
+ switch (dashArg)\r
+ {\r
+ case DASHARG_PORT:\r
+ if (pos < args.length)\r
+ {\r
+ try{\r
+ portNumber = Integer.parseInt(args[pos]);\r
+ }catch(NumberFormatException e){\r
+ consolePropertyMessage("DRDA_InvalidValue.U", \r
+ new String [] {args[pos], "DRDA_PortNumber.I"});\r
+ }\r
+ }\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", "DRDA_PortNumber.I");\r
+ break;\r
+ case DASHARG_HOST:\r
+ if (pos < args.length)\r
+ {\r
+ hostArg = args[pos];\r
+ }\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", "DRDA_Host.I");\r
+ break;\r
+ case DASHARG_DATABASE:\r
+ if (pos < args.length)\r
+ databaseArg = args[pos];\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", \r
+ "DRDA_DatabaseDirectory.I");\r
+ break;\r
+ case DASHARG_USER:\r
+ if (pos < args.length)\r
+ {\r
+ userArg = args[pos++];\r
+ if (pos < args.length)\r
+ passwordArg = args[pos];\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", \r
+ "DRDA_Password.I");\r
+ }\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", "DRDA_User.I");\r
+ break;\r
+ case DASHARG_ENCALG:\r
+ if (pos < args.length)\r
+ encAlgArg = args[pos];\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", \r
+ "DRDA_EncryptionAlgorithm.I");\r
+ break;\r
+ case DASHARG_ENCPRV:\r
+ if (pos < args.length)\r
+ encPrvArg = args[pos];\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", \r
+ "DRDA_EncryptionProvider.I");\r
+ break;\r
+ case DASHARG_LOADSYSIBM:\r
+ break;\r
+ case DASHARG_SESSION:\r
+ if (pos < args.length)\r
+ try{\r
+ sessionArg = Integer.parseInt(args[pos]);\r
+ }catch(NumberFormatException e){\r
+ consolePropertyMessage("DRDA_InvalidValue.U", \r
+ new String [] {args[pos], "DRDA_Session.I"});\r
+ }\r
+ else\r
+ consolePropertyMessage("DRDA_MissingValue.U", "DRDA_Session.I");\r
+ break;\r
+ case DASHARG_UNSECURE:\r
+ unsecureArg = true;\r
+ break;\r
+\r
+ case DASHARG_SSL:\r
+ if (pos < args.length) {\r
+ setSSLMode(getSSLModeValue(args[pos]));\r
+ } else {\r
+ setSSLMode(SSL_OFF);\r
+ }\r
+ break;\r
+\r
+ default:\r
+ //shouldn't get here\r
+ }\r
+ return pos+1;\r
+ }\r
+\r
+ /**\r
+ * Is string "on" or "off"\r
+ *\r
+ * @param arg string to check\r
+ *\r
+ * @return true if string is "on", false if string is "off"\r
+ *\r
+ * @exception Exception thrown if string is not one of "on" or "off"\r
+ */\r
+ private boolean isOn(String arg)\r
+ throws Exception\r
+ {\r
+ if (StringUtil.SQLEqualsIgnoreCase(arg, "on"))\r
+ return true;\r
+ else if (!StringUtil.SQLEqualsIgnoreCase(arg, "off"))\r
+ consolePropertyMessage("DRDA_OnOffValue.U", arg);\r
+ return false;\r
+ }\r
+ \r
+ /**\r
+ * Close the resources associated with the opened socket.\r
+ * @throws IOException\r
+ */\r
+ private void closeSocket() throws IOException\r
+ {\r
+ try {\r
+ if (clientIs != null)\r
+ clientIs.close();\r
+ if (clientOs != null)\r
+ clientOs.close();\r
+ if (clientSocket != null)\r
+ clientSocket.close();\r
+ } finally {\r
+ clientIs = null;\r
+ clientOs = null;\r
+ clientSocket = null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set up client socket to send a command to the network server\r
+ *\r
+ * @exception Exception thrown if exception encountered\r
+ */\r
+ private void setUpSocket() throws Exception\r
+ {\r
+ \r
+ try {\r
+ clientSocket = (Socket) AccessController.doPrivileged(\r
+ new PrivilegedExceptionAction() {\r
+ \r
+ public Object run() \r
+ throws UnknownHostException,\r
+ IOException, \r
+ java.security.NoSuchAlgorithmException,\r
+ java.security.KeyManagementException,\r
+ java.security.NoSuchProviderException,\r
+ java.security.KeyStoreException,\r
+ java.security.UnrecoverableKeyException,\r
+ java.security.cert.CertificateException\r
+ {\r
+ if (hostAddress == null)\r
+ hostAddress = InetAddress.getByName(hostArg);\r
+\r
+ // JDK131 can't connect with a client\r
+ // socket with 0.0.0.0 (all addresses) so we will\r
+ // getLocalHost() which will suffice.\r
+ InetAddress connectAddress;\r
+ if (JVMInfo.JDK_ID <= JVMInfo.J2SE_13 &&\r
+ hostAddress.getHostAddress().equals("0.0.0.0"))\r
+ connectAddress = InetAddress.getLocalHost();\r
+ else\r
+ connectAddress = hostAddress;\r
+\r
+ switch(getSSLMode()) {\r
+ case SSL_BASIC:\r
+ SSLSocket s1 = (SSLSocket)NaiveTrustManager.getSocketFactory().\r
+ createSocket(connectAddress, portNumber);\r
+ // Need to handshake now to get proper error reporting.\r
+ s1.startHandshake();\r
+ return s1;\r
+\r
+ case SSL_PEER_AUTHENTICATION:\r
+ SSLSocket s2 = (SSLSocket)SSLSocketFactory.getDefault().\r
+ createSocket(connectAddress, portNumber);\r
+ // Need to handshake now to get proper error reporting.\r
+ s2.startHandshake();\r
+ return s2;\r
+\r
+ case SSL_OFF:\r
+ default:\r
+ return SocketFactory.getDefault().\r
+ createSocket(connectAddress, portNumber);\r
+ }\r
+ }\r
+ }\r
+ );\r
+ } catch (PrivilegedActionException pae) {\r
+ Exception e1 = pae.getException();\r
+ if (e1 instanceof UnknownHostException) {\r
+ consolePropertyMessage("DRDA_UnknownHost.S", hostArg);\r
+ }\r
+ else if (e1 instanceof IOException) {\r
+ consolePropertyMessage("DRDA_NoIO.S",\r
+ new String [] {hostArg, \r
+ (new Integer(portNumber)).toString(), \r
+ e1.getMessage()});\r
+ }\r
+ } catch (Exception e) {\r
+ // If we find other (unexpected) errors, we ultimately exit--so make\r
+ // sure we print the error message before doing so (Beetle 5033).\r
+ throwUnexpectedException(e);\r
+ }\r
+\r
+ try\r
+ {\r
+ clientIs = clientSocket.getInputStream();\r
+ clientOs = clientSocket.getOutputStream();\r
+ } catch (IOException e) {\r
+ consolePropertyMessage("DRDA_NoInputStream.I");\r
+ throw e;\r
+ }\r
+ }\r
+\r
+ \r
+ private void checkAddressIsLocal(InetAddress inetAddr) throws UnknownHostException,Exception\r
+ {\r
+ for(int i = 0; i < localAddresses.size(); i++)\r
+ {\r
+ if (inetAddr.equals((InetAddress)localAddresses.get(i)))\r
+ {\r
+ return;\r
+ }\r
+ }\r
+ consolePropertyMessage("DRDA_NeedLocalHost.S", new String[] {inetAddr.getHostName(),serverSocket.getInetAddress().getHostName()});\r
+\r
+ }\r
+\r
+\r
+ /**\r
+ * Build local address list to allow admin commands.\r
+ *\r
+ * @param bindAddr Address on which server was started\r
+ * \r
+ * Note: Some systems may not support localhost.\r
+ * In that case a console message will print for the localhost entries,\r
+ * but the server will continue to start.\r
+ **/\r
+ private void buildLocalAddressList(InetAddress bindAddr) \r
+ {\r
+ localAddresses = new ArrayList(3);\r
+ localAddresses.add(bindAddr);\r
+ try {\r
+ localAddresses.add(InetAddress.getLocalHost());\r
+ localAddresses.add(InetAddress.getByName("localhost"));\r
+ }catch(UnknownHostException uhe)\r
+ {\r
+ try {\r
+ consolePropertyMessage("DRDA_UnknownHostWarning.I",uhe.getMessage());\r
+ } catch (Exception e)\r
+ { // just a warning shouldn't actually throw an exception\r
+ }\r
+ } \r
+ }\r
+ \r
+ /**\r
+ * Routines for writing commands for NetworkServerControlImpl being used as a client\r
+ * to a server\r
+ */\r
+\r
+ /**\r
+ * Write command header consisting of command header string and protocol\r
+ * version and command\r
+ *\r
+ * @param command command to be written\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void writeCommandHeader(int command) throws Exception\r
+ {\r
+ try {\r
+ writeString(COMMAND_HEADER);\r
+ commandOs.writeByte((byte)((PROTOCOL_VERSION & 0xf0) >> 8 ));\r
+ commandOs.writeByte((byte)(PROTOCOL_VERSION & 0x0f));\r
+\r
+ if (clientLocale != null && clientLocale != DEFAULT_LOCALE)\r
+ {\r
+ commandOs.writeByte(clientLocale.length());\r
+ commandOs.writeBytes(clientLocale);\r
+ }\r
+ else\r
+ commandOs.writeByte((byte) 0);\r
+ commandOs.writeByte((byte) 0);\r
+ commandOs.writeByte((byte) command);\r
+ }\r
+ catch (IOException e)\r
+ {\r
+ clientSocketError(e);\r
+ }\r
+ }\r
+ /**\r
+ * Write length delimited string string\r
+ *\r
+ * @param msg string to be written\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void writeLDString(String msg) throws Exception\r
+ {\r
+ try {\r
+ if (msg == null)\r
+ {\r
+ commandOs.writeShort(0);\r
+ }\r
+ else\r
+ {\r
+ commandOs.writeShort(msg.length());\r
+ writeString(msg);\r
+ }\r
+ }\r
+ catch (IOException e)\r
+ {\r
+ clientSocketError(e);\r
+ }\r
+ }\r
+\r
+ /** Write string\r
+ *\r
+ * @param msg String to write\r
+ */\r
+\r
+ protected void writeString(String msg) throws Exception\r
+ {\r
+ byte[] msgBytes = msg.getBytes(DEFAULT_ENCODING);\r
+ commandOs.write(msgBytes,0,msgBytes.length);\r
+ }\r
+\r
+ /**\r
+ * Write short\r
+ *\r
+ * @param value value to be written\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void writeShort(int value) throws Exception\r
+ {\r
+ try {\r
+ commandOs.writeByte((byte)((value & 0xf0) >> 8 ));\r
+ commandOs.writeByte((byte)(value & 0x0f));\r
+ }\r
+ catch (IOException e)\r
+ {\r
+ clientSocketError(e);\r
+ }\r
+ }\r
+ /**\r
+ * Write byte\r
+ *\r
+ * @param value value to be written\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void writeByte(int value) throws Exception\r
+ {\r
+ try {\r
+ commandOs.writeByte((byte)(value & 0x0f));\r
+ }\r
+ catch (IOException e)\r
+ {\r
+ clientSocketError(e);\r
+ }\r
+ }\r
+ /**\r
+ * Send client message to server\r
+ *\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void send() throws Exception\r
+ {\r
+ try {\r
+ byteArrayOs.writeTo(clientOs);\r
+ commandOs.flush();\r
+ byteArrayOs.reset(); //discard anything currently in the byte array\r
+ }\r
+ catch (IOException e)\r
+ {\r
+ clientSocketError(e);\r
+ }\r
+ }\r
+ /**\r
+ * Stream error writing to client socket\r
+ */\r
+ private void clientSocketError(IOException e) throws IOException\r
+ {\r
+ try {\r
+ consolePropertyMessage("DRDA_ClientSocketError.S", e.getMessage());\r
+ } catch (Exception ce) {} // catch the exception consolePropertyMessage will\r
+ // throw since we also want to print a stack trace\r
+ consoleExceptionPrintTrace(e);\r
+ throw e;\r
+ }\r
+ /**\r
+ * Read result from sending client message to server\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void readResult() throws Exception\r
+ {\r
+ fillReplyBuffer();\r
+ readCommandReplyHeader();\r
+ if (replyBufferPos >= replyBufferCount)\r
+ consolePropertyMessage("DRDA_InvalidReplyTooShort.S");\r
+ int messageType = replyBuffer[replyBufferPos++] & 0xFF;\r
+ if (messageType == OK) // O.K.\r
+ return;\r
+ // get error and display and throw exception\r
+ String message = readLDString();\r
+ if (messageType == SQLERROR)\r
+ wrapSQLError(message);\r
+ else if (messageType == SQLWARNING)\r
+ wrapSQLWarning(message);\r
+ else\r
+ consolePropertyMessage(message);\r
+ }\r
+\r
+ \r
+\r
+ /**\r
+ * Ensure the reply buffer is at large enought to hold all the data;\r
+ * don't just rely on OS level defaults\r
+ *\r
+ *\r
+ * @param minimumBytesNeeded size of buffer required \r
+ * @exception Exception throws an exception if a problem reading the reply\r
+ */\r
+ private void ensureDataInBuffer(int minimumBytesNeeded) throws Exception\r
+ {\r
+ // make sure the buffer is large enough\r
+ while ((replyBufferCount - replyBufferPos) < minimumBytesNeeded)\r
+ {\r
+ try {\r
+ int bytesRead = clientIs.read(replyBuffer, replyBufferCount, replyBuffer.length - replyBufferCount);\r
+ replyBufferCount += bytesRead;\r
+ \r
+ } catch (IOException e)\r
+ {\r
+ clientSocketError(e);\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Fill the reply buffer with the reply allocates a reply buffer if one doesn't\r
+ * exist\r
+ *\r
+ *\r
+ * @exception Exception throws an exception if a problem reading the reply\r
+ */\r
+ private void fillReplyBuffer() throws Exception\r
+ {\r
+ if (replyBuffer == null)\r
+ replyBuffer = new byte[MAXREPLY];\r
+ try {\r
+ replyBufferCount = clientIs.read(replyBuffer);\r
+ }\r
+ catch (IOException e)\r
+ {\r
+ clientSocketError(e);\r
+ }\r
+ if (replyBufferCount == -1)\r
+ consolePropertyMessage("DRDA_InvalidReplyTooShort.S");\r
+ replyBufferPos = 0;\r
+ }\r
+ /**\r
+ * Read the command reply header from the server\r
+ *\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private void readCommandReplyHeader() throws Exception\r
+ {\r
+ ensureDataInBuffer(REPLY_HEADER_LENGTH);\r
+ if (replyBufferCount < REPLY_HEADER_LENGTH)\r
+ {\r
+ consolePropertyMessage("DRDA_InvalidReplyHeader1.S", Integer.toString(replyBufferCount));\r
+ }\r
+ String header = new String(replyBuffer, 0, REPLY_HEADER_LENGTH, DEFAULT_ENCODING);\r
+ if (!header.equals(REPLY_HEADER))\r
+ {\r
+ consolePropertyMessage("DRDA_InvalidReplyHeader2.S", header);\r
+ }\r
+ replyBufferPos += REPLY_HEADER_LENGTH;\r
+ }\r
+ /**\r
+ * Read short from buffer\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private int readShort() throws Exception\r
+ {\r
+ ensureDataInBuffer(2);\r
+ if (replyBufferPos + 2 > replyBufferCount)\r
+ consolePropertyMessage("DRDA_InvalidReplyTooShort.S");\r
+ return ((replyBuffer[replyBufferPos++] & 0xff) << 8) + \r
+ (replyBuffer[replyBufferPos++] & 0xff);\r
+ }\r
+ /**\r
+ * Read int from buffer\r
+ * @exception Exception throws an exception if an error occurs\r
+ */\r
+ private int readInt() throws Exception\r
+ {\r
+ ensureDataInBuffer(4);\r
+ if (replyBufferPos + 4 > replyBufferCount)\r
+ consolePropertyMessage("DRDA_InvalidReplyTooShort.S");\r
+ return ((replyBuffer[replyBufferPos++] & 0xff) << 24) + \r
+ ((replyBuffer[replyBufferPos++] & 0xff) << 16) + \r
+ ((replyBuffer[replyBufferPos++] & 0xff) << 8) + \r
+ (replyBuffer[replyBufferPos++] & 0xff);\r
+ }\r
+ /**\r
+ * Read String reply\r
+ *\r
+ * @param msgKey error message key\r
+ * @return string value or null \r
+ * @exception Exception throws an error if problems reading reply\r
+ */\r
+ private String readStringReply(String msgKey) throws Exception\r
+ {\r
+ fillReplyBuffer();\r
+ readCommandReplyHeader();\r
+ if (replyBuffer[replyBufferPos++] == 0) // O.K.\r
+ return readLDString();\r
+ else\r
+ consolePropertyMessage(msgKey);\r
+ return null;\r
+ \r
+ }\r
+\r
+\r
+\r
+ \r
+ /**\r
+ * Read length delimited string from a buffer\r
+ *\r
+ * @return string value from buffer\r
+ * @exception Exception throws an error if problems reading reply\r
+ */\r
+ private String readLDString() throws Exception\r
+ {\r
+ int strlen = readShort();\r
+ ensureDataInBuffer(strlen);\r
+ if (replyBufferPos + strlen > replyBufferCount)\r
+ consolePropertyMessage("DRDA_InvalidReplyTooShort.S");\r
+ String retval= new String(replyBuffer, replyBufferPos, strlen, DEFAULT_ENCODING);\r
+ replyBufferPos += strlen;\r
+ return retval;\r
+ }\r
+ /**\r
+ * Read Bytes reply\r
+ *\r
+ * @param msgKey error message key\r
+ * @return string value or null \r
+ * @exception Exception throws an error if problems reading reply\r
+ */\r
+ private byte [] readBytesReply(String msgKey) throws Exception\r
+ {\r
+ fillReplyBuffer();\r
+ readCommandReplyHeader();\r
+ if (replyBuffer[replyBufferPos++] == 0) // O.K.\r
+ return readLDBytes();\r
+ else\r
+ consolePropertyMessage(msgKey);\r
+ return null;\r
+ \r
+ }\r
+ /**\r
+ * Read length delimited bytes from a buffer\r
+ *\r
+ * @return byte array from buffer\r
+ * @exception Exception throws an error if problems reading reply\r
+ */\r
+ private byte[] readLDBytes() throws Exception\r
+ {\r
+ int len = readShort();\r
+ ensureDataInBuffer(len);\r
+ if (replyBufferPos + len > replyBufferCount)\r
+ consolePropertyMessage("DRDA_InvalidReplyTooShort.S");\r
+ byte [] retval = new byte[len];\r
+ for (int i = 0; i < len; i++)\r
+ retval[i] = replyBuffer[replyBufferPos++];\r
+ return retval;\r
+ }\r
+\r
+ /**\r
+ * Initialize fields from system properties\r
+ *\r
+ */\r
+ private void getPropertyInfo() throws Exception\r
+ {\r
+ //set values according to properties\r
+ \r
+ String directory = PropertyUtil.getSystemProperty(Property.SYSTEM_HOME_PROPERTY);\r
+ String propval = PropertyUtil.getSystemProperty(\r
+ Property.DRDA_PROP_LOGCONNECTIONS);\r
+ if (propval != null && StringUtil.SQLEqualsIgnoreCase(propval,"true")) \r
+ setLogConnections(true);\r
+ propval = PropertyUtil.getSystemProperty(Property.DRDA_PROP_TRACEALL);\r
+ if (propval != null && StringUtil.SQLEqualsIgnoreCase(propval, \r
+ "true")) \r
+ setTraceAll(true);\r
+\r
+ //If the derby.system.home property has been set, it is the default. \r
+ //Otherwise, the default is the current directory. \r
+ //If derby.system.home is not set, directory will be null and trace files will get\r
+ //created in current directory.\r
+ propval = PropertyUtil.getSystemProperty(Property.DRDA_PROP_TRACEDIRECTORY,directory);\r
+ if(propval != null){\r
+ if(propval.equals(""))\r
+ propval = directory;\r
+ setTraceDirectory(propval);\r
+ }\r
+\r
+ //DERBY-375 If a system property is specified without any value, getProperty returns \r
+ //an empty string. Use default values in such cases.\r
+ propval = PropertyUtil.getSystemProperty( \r
+ Property.DRDA_PROP_MINTHREADS);\r
+ if (propval != null){\r
+ if(propval.equals(""))\r
+ propval = "0";\r
+ setMinThreads(getIntPropVal(Property.DRDA_PROP_MINTHREADS, propval));\r
+ }\r
+\r
+ propval = PropertyUtil.getSystemProperty( \r
+ Property.DRDA_PROP_MAXTHREADS);\r
+ if (propval != null){\r
+ if(propval.equals(""))\r
+ propval = "0";\r
+ setMaxThreads(getIntPropVal(Property.DRDA_PROP_MAXTHREADS, propval));\r
+ }\r
+\r
+\r
+ propval = PropertyUtil.getSystemProperty( \r
+ Property.DRDA_PROP_TIMESLICE);\r
+ if (propval != null){\r
+ if(propval.equals(""))\r
+ propval = "0";\r
+ setTimeSlice(getIntPropVal(Property.DRDA_PROP_TIMESLICE, propval));\r
+ }\r
+\r
+ propval = PropertyUtil.getSystemProperty( \r
+ Property.DRDA_PROP_PORTNUMBER);\r
+ if (propval != null){\r
+ if(propval.equals(""))\r
+ propval = String.valueOf(NetworkServerControl.DEFAULT_PORTNUMBER);\r
+ portNumber = getIntPropVal(Property.DRDA_PROP_PORTNUMBER, propval);\r
+ }\r
+\r
+ propval = PropertyUtil.getSystemProperty(\r
+ Property.DRDA_PROP_SSL_MODE);\r
+ setSSLMode(getSSLModeValue(propval));\r
+ \r
+ propval = PropertyUtil.getSystemProperty( \r
+ Property.DRDA_PROP_KEEPALIVE);\r
+ if (propval != null && \r
+ StringUtil.SQLEqualsIgnoreCase(propval,"false"))\r
+ keepAlive = false;\r
+ \r
+ propval = PropertyUtil.getSystemProperty( \r
+ Property.DRDA_PROP_HOSTNAME);\r
+ if (propval != null){\r
+ if(propval.equals(""))\r
+ hostArg = DEFAULT_HOST; \r
+ else\r
+ hostArg = propval;\r
+ } \r
+ propval = PropertyUtil.getSystemProperty(\r
+ NetworkServerControlImpl.DRDA_PROP_DEBUG);\r
+ if (propval != null && StringUtil.SQLEqualsIgnoreCase(propval, "true"))\r
+ debugOutput = true;\r
+\r
+ propval = PropertyUtil.getSystemProperty( \r
+ Property.DRDA_PROP_SECURITYMECHANISM);\r
+ if (propval != null){\r
+ setSecurityMechanism(propval);\r
+ }\r
+\r
+ }\r
+\r
+ /**\r
+ * Retrieve the SECMEC integer value from the\r
+ * user friendly security mechanism name\r
+ * @param s security mechanism name\r
+ * @return integer value , return the SECMEC value for \r
+ * the security mechanism as defined by DRDA spec\r
+ * or INVALID_OR_NOTSET_SECURITYMECHANISM if 's'\r
+ * passed is invalid or not supported security \r
+ * mechanism\r
+ */\r
+ private int getSecMecValue(String s)\r
+ {\r
+ int secmec = INVALID_OR_NOTSET_SECURITYMECHANISM;\r
+\r
+ if( StringUtil.SQLEqualsIgnoreCase(s,"USER_ONLY_SECURITY"))\r
+ secmec = CodePoint.SECMEC_USRIDONL;\r
+ else if( StringUtil.SQLEqualsIgnoreCase(s,"CLEAR_TEXT_PASSWORD_SECURITY"))\r
+ secmec = CodePoint.SECMEC_USRIDPWD;\r
+ else if( StringUtil.SQLEqualsIgnoreCase(s,"ENCRYPTED_USER_AND_PASSWORD_SECURITY"))\r
+ secmec = CodePoint.SECMEC_EUSRIDPWD;\r
+ else if( StringUtil.SQLEqualsIgnoreCase(s,"STRONG_PASSWORD_SUBSTITUTE_SECURITY"))\r
+ secmec = CodePoint.SECMEC_USRSSBPWD;\r
+ \r
+ return secmec;\r
+ }\r
+\r
+ /**\r
+ * Retrieve the string name for the integer\r
+ * secmec value\r
+ * @param secmecVal secmec value\r
+ * @return String - return the string name corresponding \r
+ * to the secmec value if recognized else returns null\r
+ */\r
+ private String getStringValueForSecMec(int secmecVal)\r
+ {\r
+ switch(secmecVal)\r
+ {\r
+ case CodePoint.SECMEC_USRIDONL:\r
+ return "USER_ONLY_SECURITY";\r
+ \r
+ case CodePoint.SECMEC_USRIDPWD:\r
+ return "CLEAR_TEXT_PASSWORD_SECURITY";\r
+ \r
+ case CodePoint.SECMEC_EUSRIDPWD:\r
+ return "ENCRYPTED_USER_AND_PASSWORD_SECURITY";\r
+ \r
+ case CodePoint.SECMEC_USRSSBPWD:\r
+ return "STRONG_PASSWORD_SUBSTITUTE_SECURITY";\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ /**\r
+ * This method returns whether EUSRIDPWD security mechanism\r
+ * is supported or not. See class static block for more\r
+ * info.\r
+ * @return true if EUSRIDPWD is supported, false otherwise\r
+ */ \r
+ boolean supportsEUSRIDPWD()\r
+ {\r
+ return SUPPORTS_EUSRIDPWD;\r
+ }\r
+ \r
+ /**\r
+ * Get the SSL-mode from a string.\r
+ * @param s the SSL-mode string ("off"/"false", "on"/"true" or\r
+ * "authenticate"/"auth"\r
+ * @return SSL_OFF, SSL_BASIC or SSL_PEER_AUTHENTICATION. Will default to\r
+ * SSL_OFF if the input does not match one of the four listed\r
+ * above.\r
+ **/\r
+\r
+ private int getSSLModeValue(String s)\r
+ throws Exception\r
+ {\r
+ if (s != null){\r
+ if (StringUtil.SQLEqualsIgnoreCase(s,"off")) {\r
+ return SSL_OFF;\r
+ } else if (StringUtil.SQLEqualsIgnoreCase(s,"basic")) {\r
+ return SSL_BASIC;\r
+ } else if (StringUtil.SQLEqualsIgnoreCase(s,"peerAuthentication")) {\r
+ return SSL_PEER_AUTHENTICATION;\r
+ } else {\r
+ // Unknown value\r
+ consolePropertyMessage("DRDA_InvalidValue.U", \r
+ new String [] {s, Property.DRDA_PROP_SSL_MODE});\r
+ \r
+ return SSL_OFF;\r
+ }\r
+ } else {\r
+ // Default\r
+ return SSL_OFF;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the string value of the SSL-mode. This is the inverse of\r
+ * getSSLModeValue.\r
+ * @param i The SSL-mode value (SSL_OFF, SSL_BASIC or\r
+ * SSL_PEER_AUTHENTICATION)\r
+ * @return The string representation ("off","on" or\r
+ * "autneticate"). Will default to SSL_OFF for other values than\r
+ * those listed above.\r
+ */\r
+ \r
+ private String getSSLModeString(int i)\r
+ {\r
+ switch(i) {\r
+ case SSL_OFF:\r
+ return "off";\r
+ case SSL_BASIC:\r
+ return "basic";\r
+ case SSL_PEER_AUTHENTICATION:\r
+ return "peerAuthentication";\r
+ default: \r
+ // Assumes no SSL encryption for faulty values Anyway,\r
+ // this should not happen thince the input values are\r
+ // strings...\r
+ return "off";\r
+ }\r
+ }\r
+\r
+ \r
+ /**\r
+ * Get integer property values\r
+ *\r
+ * @param propName property name\r
+ * @param propVal string property value\r
+ * @return integer value\r
+ *\r
+ * @exception Exception if not a valid integer\r
+ */\r
+ private int getIntPropVal(String propName, String propVal)\r
+ throws Exception\r
+ {\r
+ int val = 0;\r
+ try {\r
+ val = (new Integer(propVal)).intValue();\r
+ } catch (Exception e)\r
+ {\r
+ consolePropertyMessage("DRDA_InvalidPropVal.S", new String [] \r
+ {propName, propVal});\r
+ }\r
+ return val;\r
+ }\r
+\r
+ /**\r
+ * Handle console error message\r
+ * - display on console and if it is a user error, display usage\r
+ * - if user error or severe error, throw exception with message key and message\r
+ *\r
+ * @param messageKey message key\r
+ * @param args arguments to message\r
+ *\r
+ * @throws Exception if an error occurs\r
+ */\r
+ private void consolePropertyMessageWork(String messageKey, String [] args)\r
+ throws Exception\r
+ {\r
+ String locMsg = null;\r
+\r
+ int type = getMessageType(messageKey);\r
+\r
+ if (type == ERRTYPE_UNKNOWN)\r
+ locMsg = messageKey;\r
+ else\r
+ locMsg = localizeMessage(messageKey, langUtil, args);\r
+\r
+ //display on the console\r
+ consoleMessage(locMsg);\r
+\r
+ //if it is a user error display usage\r
+ if (type == ERRTYPE_USER)\r
+ usage();\r
+\r
+ //we may want to use a different locale for throwing the exception\r
+ //since this can be sent to a browser with a different locale\r
+ if (currentSession != null && \r
+ currentSession.langUtil != null &&\r
+ type != ERRTYPE_UNKNOWN)\r
+ locMsg = localizeMessage(messageKey, currentSession.langUtil, args);\r
+\r
+ // throw an exception for severe and user errors\r
+ if (type == ERRTYPE_SEVERE || type == ERRTYPE_USER)\r
+ {\r
+ if (messageKey.equals("DRDA_SQLException.S"))\r
+ throwSQLException(args[0]);\r
+ else if (messageKey.equals("DRDA_SQLWarning.I"))\r
+ throwSQLWarning(args[0]);\r
+ else \r
+ throw new Exception(messageKey+":"+locMsg);\r
+ }\r
+\r
+ // throw an exception with just the message if the error type is\r
+ // unknown\r
+ if (type == ERRTYPE_UNKNOWN)\r
+ throw new Exception(locMsg);\r
+\r
+ return;\r
+\r
+ }\r
+ /**\r
+ * Throw a SQL Exception which was sent over by a server\r
+ * Format of the msg is SQLSTATE:localized message\nSQLSTATE:next localized message\r
+ *\r
+ * @param msg msg containing SQL Exception\r
+ *\r
+ * @throws SQLException\r
+ */\r
+ private void throwSQLException(String msg) throws SQLException\r
+ {\r
+ SQLException se = null;\r
+ SQLException ne;\r
+ SQLException ce = null;\r
+ StringBuffer strbuf = new StringBuffer();\r
+ StringTokenizer tokenizer = new StringTokenizer(msg, "\n");\r
+ String sqlstate = null;\r
+ String str;\r
+ while (tokenizer.hasMoreTokens())\r
+ {\r
+ str = tokenizer.nextToken();\r
+ //start of the next message\r
+ if (str.charAt(5) == ':')\r
+ {\r
+ if (strbuf.length() > 0)\r
+ {\r
+ if (se == null)\r
+ {\r
+ se = new SQLException(strbuf.toString(), sqlstate);\r
+ ce = se;\r
+ }\r
+ else\r
+ {\r
+ ne = new SQLException(strbuf.toString(), sqlstate);\r
+ ce.setNextException(ne);\r
+ ce = ne;\r
+ }\r
+ strbuf = new StringBuffer();\r
+ }\r
+ strbuf.append(str.substring(6));\r
+ sqlstate = str.substring(0,5);\r
+ }\r
+ else\r
+ strbuf.append(str);\r
+ }\r
+ if (strbuf.length() > 0)\r
+ {\r
+ if (se == null)\r
+ {\r
+ se = new SQLException(strbuf.toString(), sqlstate);\r
+ ce = se;\r
+ }\r
+ else\r
+ {\r
+ ne = new SQLException(strbuf.toString(), sqlstate);\r
+ ce.setNextException(ne);\r
+ ce = ne;\r
+ }\r
+ }\r
+ throw se;\r
+ }\r
+ /**\r
+ * Throw a SQL Warning which was sent over by a server\r
+ * Format of the msg is SQLSTATE:localized message\nSQLSTATE:next localized message\r
+ *\r
+ * @param msg msg containing SQL Warning\r
+ *\r
+ * @throws SQLWarning\r
+ */\r
+ private void throwSQLWarning(String msg) throws SQLWarning\r
+ {\r
+ SQLWarning se = null;\r
+ SQLWarning ne;\r
+ SQLWarning ce = null;\r
+ StringBuffer strbuf = new StringBuffer();\r
+ StringTokenizer tokenizer = new StringTokenizer(msg, "\n");\r
+ String sqlstate = null;\r
+ String str;\r
+ while (tokenizer.hasMoreTokens())\r
+ {\r
+ str = tokenizer.nextToken();\r
+ //start of the next message\r
+ if (str.charAt(5) == ':')\r
+ {\r
+ if (strbuf.length() > 0)\r
+ {\r
+ if (se == null)\r
+ {\r
+ se = new SQLWarning(strbuf.toString(), sqlstate);\r
+ ce = se;\r
+ }\r
+ else\r
+ {\r
+ ne = new SQLWarning(strbuf.toString(), sqlstate);\r
+ ce.setNextException(ne);\r
+ ce = ne;\r
+ }\r
+ strbuf = new StringBuffer();\r
+ }\r
+ strbuf.append(str.substring(6));\r
+ sqlstate = str.substring(0,5);\r
+ }\r
+ else\r
+ strbuf.append(str);\r
+ }\r
+ if (strbuf.length() > 0)\r
+ {\r
+ if (se == null)\r
+ {\r
+ se = new SQLWarning(strbuf.toString(), sqlstate);\r
+ ce = se;\r
+ }\r
+ else\r
+ {\r
+ ne = new SQLWarning(strbuf.toString(), sqlstate);\r
+ ce.setNextException(ne);\r
+ ce = ne;\r
+ }\r
+ }\r
+ throw se;\r
+ }\r
+\r
+ /**\r
+ * Print a trace for the (unexpected) exception received, then\r
+ * throw a generic exception indicating that 1) an unexpected\r
+ * exception was thrown, and 2) we've already printed the trace\r
+ * (so don't do it again).\r
+ * \r
+ * @param e An unexpected exception.\r
+ * @throws Exception with message UNEXPECTED_ERR.\r
+ */\r
+ private void throwUnexpectedException(Exception e)\r
+ throws Exception {\r
+\r
+ consoleExceptionPrintTrace(e);\r
+ throw new Exception(UNEXPECTED_ERR);\r
+\r
+ }\r
+\r
+ /**\r
+ * Convenience routine so that NetworkServerControl can localize messages.\r
+ *\r
+ * @param msgProp message key\r
+ * @param args arguments to message\r
+ *\r
+ */\r
+ public String localizeMessage( String msgProp, String[] args )\r
+ {\r
+ return localizeMessage( msgProp, langUtil, args );\r
+ }\r
+\r
+ /**\r
+ * Localize a message given a particular AppUI \r
+ *\r
+ * @param msgProp message key\r
+ * @param localLangUtil LocalizedResource to use to localize message\r
+ * @param args arguments to message\r
+ *\r
+ */\r
+ private String localizeMessage(String msgProp, LocalizedResource localLangUtil, String [] args)\r
+ {\r
+ String locMsg = null;\r
+ //check if the argument is a property\r
+ if (args != null)\r
+ {\r
+ String [] argMsg = new String[args.length];\r
+ for (int i = 0; i < args.length; i++)\r
+ {\r
+ if (isMsgProperty(args[i]))\r
+ argMsg[i] = localLangUtil.getTextMessage(args[i]);\r
+ else\r
+ argMsg[i] = args[i];\r
+ }\r
+ switch (args.length)\r
+ {\r
+ case 1:\r
+ locMsg = localLangUtil.getTextMessage(msgProp, argMsg[0]);\r
+ break;\r
+ case 2:\r
+ locMsg = localLangUtil.getTextMessage(msgProp, argMsg[0], argMsg[1]);\r
+ break;\r
+ case 3:\r
+ locMsg = localLangUtil.getTextMessage(msgProp, argMsg[0], argMsg[1], argMsg[2]);\r
+ break;\r
+ case 4:\r
+ locMsg = localLangUtil.getTextMessage(msgProp, argMsg[0], argMsg[1], argMsg[2], argMsg[3]);\r
+ break;\r
+ default:\r
+ //shouldn't get here\r
+ }\r
+ }\r
+ else\r
+ locMsg = localLangUtil.getTextMessage(msgProp);\r
+ return locMsg;\r
+ }\r
+ /**\r
+ * Determine type of message\r
+ *\r
+ * @param msg message \r
+ *\r
+ * @return message type\r
+ */\r
+ private int getMessageType(String msg)\r
+ {\r
+ //all property messages should start with DRDA_\r
+ if (!msg.startsWith(DRDA_MSG_PREFIX))\r
+ return ERRTYPE_UNKNOWN;\r
+ int startpos = msg.indexOf('.')+1;\r
+ if (startpos >= msg.length())\r
+ return ERRTYPE_UNKNOWN;\r
+ if (msg.length() > (startpos + 1))\r
+ return ERRTYPE_UNKNOWN;\r
+ char type = msg.charAt(startpos);\r
+ if (type == 'S')\r
+ return ERRTYPE_SEVERE;\r
+ if (type == 'U')\r
+ return ERRTYPE_USER;\r
+ if (type == 'I')\r
+ return ERRTYPE_INFO;\r
+ return ERRTYPE_UNKNOWN;\r
+ }\r
+ /**\r
+ * Determine whether string is a property key or not\r
+ * property keys start with DRDA_MSG_PREFIX\r
+ *\r
+ * @param msg message \r
+ *\r
+ * @return true if it is a property key; false otherwise\r
+ */\r
+ private boolean isMsgProperty(String msg)\r
+ {\r
+ if (msg.startsWith(DRDA_MSG_PREFIX))\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ /**\r
+ * Get the current value of logging connections\r
+ *\r
+ * @return true if logging connections is on; false otherwise\r
+ */\r
+ public boolean getLogConnections()\r
+ {\r
+ synchronized(logConnectionsSync) {\r
+ return logConnections;\r
+ }\r
+ }\r
+ /**\r
+ * Set the current value of logging connections\r
+ *\r
+ * @param value true to turn logging connections on; false to turn it off\r
+ */\r
+ private void setLogConnections(boolean value)\r
+ {\r
+ synchronized(logConnectionsSync) {\r
+ logConnections = value;\r
+ }\r
+ // update the value in all the threads\r
+ synchronized(threadList) {\r
+ for (Enumeration e = threadList.elements(); e.hasMoreElements(); )\r
+ {\r
+ DRDAConnThread thread = (DRDAConnThread)e.nextElement();\r
+ thread.setLogConnections(value);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set the security mechanism for derby.drda.securityMechanism\r
+ * If this property is set, server will only allow connections\r
+ * from client with this security mechanism.\r
+ * This method will map the user friendly string representing \r
+ * the security mechanism to the corresponding drda secmec value\r
+ * @param s security mechanism string value\r
+ * @throws Exception if value to set is invalid\r
+ * @see Property#DRDA_PROP_SECURITYMECHANISM \r
+ */\r
+ private void setSecurityMechanism(String s)\r
+ throws Exception\r
+ {\r
+ allowOnlySecurityMechanism = getSecMecValue(s);\r
+ \r
+ // if server vm cannot support EUSRIDPWD, then do not allow \r
+ // derby.drda.securityMechanism to be set to EUSRIDPWD security\r
+ // mechanism\r
+ if ((allowOnlySecurityMechanism == INVALID_OR_NOTSET_SECURITYMECHANISM) ||\r
+ (allowOnlySecurityMechanism == CodePoint.SECMEC_EUSRIDPWD &&\r
+ !SUPPORTS_EUSRIDPWD))\r
+ consolePropertyMessage("DRDA_InvalidValue.U", new String [] \r
+ {s, Property.DRDA_PROP_SECURITYMECHANISM});\r
+ }\r
+ \r
+ /**\r
+ * get the security mechanism (secmec value) that the server\r
+ * will accept connections from.\r
+ * @return the securitymechanism value. It is value that \r
+ * the derby.drda.securityMechanism was set to, if it is not set, then\r
+ * it is equal to INVALID_OR_NOTSET_SECURITYMECHANISM\r
+ * @see Property#DRDA_PROP_SECURITYMECHANISM \r
+ */\r
+ protected int getSecurityMechanism()\r
+ {\r
+ return allowOnlySecurityMechanism;\r
+ }\r
+ /**\r
+ * Set the trace on/off for all sessions, or one session, depending on\r
+ * whether we got -s argument.\r
+ *\r
+ * @param on true to turn trace on; false to turn it off\r
+ * @return true if set false if an error occurred\r
+ */\r
+ private boolean setTrace(boolean on)\r
+ {\r
+ boolean setTraceSuccessful = true;\r
+ if (sessionArg == 0)\r
+ {\r
+ synchronized(sessionTable) {\r
+ for (Enumeration e = sessionTable.elements(); e.hasMoreElements(); )\r
+ {\r
+ \r
+ Session session = (Session) e.nextElement();\r
+ if (on)\r
+ try {\r
+ session.setTraceOn(traceDirectory);\r
+ } catch (Exception te ) {\r
+ consoleExceptionPrintTrace(te);\r
+ setTraceSuccessful = false;\r
+ session.setTraceOff();\r
+ }\r
+ else\r
+ session.setTraceOff();\r
+ }\r
+ if (setTraceSuccessful)\r
+ setTraceAll(on);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ Session session = (Session) sessionTable.get(new Integer(sessionArg));\r
+ if (session != null)\r
+ { \r
+ if (on)\r
+ try { \r
+ session.setTraceOn(traceDirectory);\r
+ }catch (Exception te) {\r
+ consoleExceptionPrintTrace(te);\r
+ setTraceSuccessful = false;\r
+ session.setTraceOff();\r
+ }\r
+ else\r
+ session.setTraceOff();\r
+ }\r
+ else\r
+ return false;\r
+ }\r
+ return setTraceSuccessful;\r
+ }\r
+\r
+\r
+ /**\r
+ * Get the current value of the time slice\r
+ *\r
+ * @return time slice value\r
+ */\r
+ protected int getTimeSlice()\r
+ {\r
+ return timeSlice;\r
+ }\r
+ /**\r
+ * Set the current value of time slice\r
+ *\r
+ * @param value time slice value\r
+ * @exception Exception if value is < 0\r
+ */\r
+ private void setTimeSlice(int value)\r
+ throws Exception\r
+ {\r
+ if (value < MIN_TIMESLICE)\r
+ consolePropertyMessage("DRDA_InvalidValue.U", new String [] \r
+ {new Integer(value).toString(), "timeslice"});\r
+ if (value == USE_DEFAULT)\r
+ value = DEFAULT_TIMESLICE;\r
+ synchronized(timeSliceSync) {\r
+ timeSlice = value;\r
+ }\r
+ }\r
+ \r
+ /** \r
+ * Get the current value of keepAlive to configure how long the server\r
+ * should keep the socket alive for a disconnected client\r
+ */\r
+ protected boolean getKeepAlive()\r
+ {\r
+ return keepAlive;\r
+ }\r
+\r
+ /**\r
+ * Get the current value of minimum number of threads to create at start\r
+ *\r
+ * @return value of minimum number of threads\r
+ */\r
+ private int getMinThreads()\r
+ {\r
+ synchronized(threadsSync) {\r
+ return minThreads;\r
+ }\r
+ }\r
+ /**\r
+ * Set the current value of minimum number of threads to create at start\r
+ *\r
+ * @param value value of minimum number of threads\r
+ */\r
+ private void setMinThreads(int value)\r
+ {\r
+ synchronized(threadsSync) {\r
+ minThreads = value;\r
+ }\r
+ }\r
+ /**\r
+ * Get the current value of maximum number of threads to create \r
+ *\r
+ * @return value of maximum number of threads\r
+ */\r
+ private int getMaxThreads()\r
+ {\r
+ synchronized(threadsSync) {\r
+ return maxThreads;\r
+ }\r
+ }\r
+ /**\r
+ * Set the current value of maximum number of threads to create \r
+ *\r
+ * @param value value of maximum number of threads\r
+ * @exception Exception if value is less than 0\r
+ */\r
+ private void setMaxThreads(int value) throws Exception\r
+ {\r
+ if (value < MIN_MAXTHREADS)\r
+ consolePropertyMessage("DRDA_InvalidValue.U", new String [] \r
+ {new Integer(value).toString(), "maxthreads"});\r
+ if (value == USE_DEFAULT)\r
+ value = DEFAULT_MAXTHREADS;\r
+ synchronized(threadsSync) {\r
+ maxThreads = value;\r
+ }\r
+ }\r
+\r
+ protected void setSSLMode(int mode)\r
+ {\r
+ sslMode = mode;\r
+ }\r
+\r
+ protected int getSSLMode() \r
+ {\r
+ return sslMode;\r
+ }\r
+ \r
+ /**\r
+ * Get the current value of whether to trace all the sessions\r
+ *\r
+ * @return true if tracing is on for all sessions; false otherwise\r
+ */\r
+ protected boolean getTraceAll()\r
+ {\r
+ synchronized(traceAllSync) {\r
+ return traceAll;\r
+ }\r
+ }\r
+ /**\r
+ * Set the current value of whether to trace all the sessions\r
+ *\r
+ * @param value true if tracing is on for all sessions; false otherwise\r
+ */\r
+ private void setTraceAll(boolean value)\r
+ {\r
+ synchronized(traceAllSync) {\r
+ traceAll = value;\r
+ }\r
+ }\r
+ /**\r
+ * Get the current value of trace directory\r
+ *\r
+ * @return trace directory\r
+ */\r
+ protected String getTraceDirectory()\r
+ {\r
+ synchronized(traceDirectorySync) {\r
+ return traceDirectory;\r
+ }\r
+ }\r
+ /**\r
+ * Set the current value of trace directory\r
+ *\r
+ * @param value trace directory\r
+ */\r
+ private void setTraceDirectory(String value)\r
+ {\r
+ synchronized(traceDirectorySync) {\r
+ traceDirectory = value;\r
+ }\r
+ }\r
+\r
+ \r
+\r
+ /**\r
+ * Connect to a database to test whether a connection can be made\r
+ *\r
+ * @param writer connection to send message to\r
+ * @param database database directory to connect to\r
+ * @param user user to use\r
+ * @param password password to use\r
+ */\r
+ private void connectToDatabase(DDMWriter writer, String database, String user, \r
+ String password) throws Exception\r
+ {\r
+ Properties p = new Properties();\r
+ if (user != null)\r
+ p.put("user", user);\r
+ if (password != null)\r
+ p.put("password", password);\r
+ try {\r
+ Class.forName(CLOUDSCAPE_DRIVER);\r
+ //Added by Jeff Huang\r
+ new org.apache.derby.jdbc.EmbeddedDriver();\r
+ }\r
+ catch (Exception e) {\r
+ sendMessage(writer, ERROR, e.getMessage());\r
+ return;\r
+ }\r
+ try {\r
+ //Note, we add database to the url so that we can allow additional\r
+ //url attributes\r
+ Connection conn = DriverManager.getConnection(Attribute.PROTOCOL+database, p);\r
+ // send warnings\r
+ SQLWarning warn = conn.getWarnings();\r
+ if (warn != null)\r
+ sendSQLMessage(writer, warn, SQLWARNING);\r
+ else\r
+ sendOK(writer);\r
+ conn.close();\r
+ return;\r
+ } catch (SQLException se) {\r
+ sendSQLMessage(writer, se, SQLERROR);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Wrap SQL Error - display to console and raise exception\r
+ *\r
+ * @param messageKey Derby SQL Exception message id\r
+ *\r
+ * @exception Exception raises exception for message\r
+ */\r
+ private void wrapSQLError(String messageKey)\r
+ throws Exception\r
+ {\r
+ consolePropertyMessage("DRDA_SQLException.S", messageKey);\r
+ }\r
+\r
+ /**\r
+ * Wrap SQL Warning - display to console and raise exception\r
+ *\r
+ * @param messageKey Derby SQL Exception message id\r
+ *\r
+ * @exception Exception raises exception for message\r
+ */\r
+ private void wrapSQLWarning(String messageKey)\r
+ throws Exception\r
+ {\r
+ consolePropertyMessage("DRDA_SQLWarning.I", messageKey);\r
+ }\r
+ private Properties getPropertyValues()\r
+ {\r
+ Properties retval = new Properties();\r
+ retval.put(Property.DRDA_PROP_PORTNUMBER, new Integer(portNumber).toString());\r
+ retval.put(Property.DRDA_PROP_HOSTNAME, hostArg);\r
+ retval.put(Property.DRDA_PROP_KEEPALIVE, new Boolean(keepAlive).toString());\r
+\r
+ String tracedir = getTraceDirectory();\r
+ if (tracedir != null)\r
+ retval.put(Property.DRDA_PROP_TRACEDIRECTORY, tracedir);\r
+ retval.put(Property.DRDA_PROP_TRACEALL, new Boolean(getTraceAll()).toString());\r
+ retval.put(Property.DRDA_PROP_MINTHREADS, new Integer(getMinThreads()).toString());\r
+ retval.put(Property.DRDA_PROP_MAXTHREADS, new Integer(getMaxThreads()).toString());\r
+ retval.put(Property.DRDA_PROP_TIMESLICE, new Integer(getTimeSlice()).toString());\r
+\r
+ retval.put(Property.DRDA_PROP_TIMESLICE, new Integer(getTimeSlice()).toString());\r
+ retval.put(Property.DRDA_PROP_LOGCONNECTIONS, new Boolean(getLogConnections()).toString());\r
+ String startDRDA = PropertyUtil.getSystemProperty(Property.START_DRDA);\r
+ //DERBY-375 If a system property is specified without any value, getProperty returns \r
+ //an empty string. Use default values in such cases.\r
+ if(startDRDA!=null && startDRDA.equals(""))\r
+ startDRDA = "false";\r
+\r
+ retval.put(Property.START_DRDA, (startDRDA == null)? "false" : startDRDA);\r
+\r
+ // DERBY-2108 SSL\r
+ retval.put(Property.DRDA_PROP_SSL_MODE, getSSLModeString(getSSLMode()));\r
+ \r
+ // if Property.DRDA_PROP_SECURITYMECHANISM has been set on server\r
+ // then put it in retval else the default behavior is as though \r
+ // it is not set\r
+ if ( getSecurityMechanism() != INVALID_OR_NOTSET_SECURITYMECHANISM )\r
+ retval.put( Property.DRDA_PROP_SECURITYMECHANISM, getStringValueForSecMec(getSecurityMechanism()));\r
+ \r
+ //get the trace value for each session if tracing for all is not set\r
+ if (!getTraceAll())\r
+ {\r
+ synchronized(sessionTable) {\r
+ for (Enumeration e = sessionTable.elements(); e.hasMoreElements(); )\r
+ { \r
+ Session session = (Session) e.nextElement();\r
+ if (session.isTraceOn())\r
+ retval.put(Property.DRDA_PROP_TRACE+"."+session.getConnNum(), "true");\r
+ }\r
+ }\r
+ }\r
+ return retval;\r
+ }\r
+\r
+\r
+ /**\r
+ * Add a session - for use by <code>ClientThread</code>. Put the session\r
+ * into the session table and the run queue. Start a new\r
+ * <code>DRDAConnThread</code> if there are more sessions waiting than\r
+ * there are free threads, and the maximum number of threads is not\r
+ * exceeded.\r
+ *\r
+ * <p><code>addSession()</code> should only be called from one thread at a\r
+ * time.\r
+ *\r
+ * @param clientSocket the socket to read from and write to\r
+ */\r
+ void addSession(Socket clientSocket) throws Exception {\r
+\r
+ int connectionNumber = ++connNum;\r
+\r
+ if (getLogConnections()) {\r
+ consolePropertyMessage("DRDA_ConnNumber.I",\r
+ Integer.toString(connectionNumber));\r
+ }\r
+\r
+ // Note that we always re-fetch the tracing configuration because it\r
+ // may have changed (there are administrative commands which allow\r
+ // dynamic tracing reconfiguration).\r
+ Session session = new Session(connectionNumber, clientSocket,\r
+ getTraceDirectory(), getTraceAll());\r
+\r
+ sessionTable.put(new Integer(connectionNumber), session);\r
+\r
+ // Check whether there are enough free threads to service all the\r
+ // threads in the run queue in addition to the newly added session.\r
+ boolean enoughThreads;\r
+ synchronized (runQueue) {\r
+ enoughThreads = (runQueue.size() < freeThreads);\r
+ }\r
+ // No need to hold the synchronization on runQueue any longer than\r
+ // this. Since no other threads can make runQueue grow, and no other\r
+ // threads will reduce the number of free threads without removing\r
+ // sessions from runQueue, (runQueue.size() < freeThreads) cannot go\r
+ // from true to false until addSession() returns.\r
+\r
+ DRDAConnThread thread = null;\r
+\r
+ // try to start a new thread if we don't have enough free threads\r
+ if (!enoughThreads) {\r
+ // Synchronize on threadsSync to ensure that the value of\r
+ // maxThreads doesn't change until the new thread is added to\r
+ // threadList.\r
+ synchronized (threadsSync) {\r
+ // only start a new thread if we have no maximum number of\r
+ // threads or the maximum number of threads is not exceeded\r
+ if ((maxThreads == 0) || (threadList.size() < maxThreads)) {\r
+ thread = new DRDAConnThread(session, this, getTimeSlice(),\r
+ getLogConnections());\r
+ threadList.add(thread);\r
+ thread.start();\r
+ }\r
+ }\r
+ }\r
+\r
+ // add the session to the run queue if we didn't start a new thread\r
+ if (thread == null) {\r
+ runQueueAdd(session);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Remove a thread from the thread list. Should be called when a\r
+ * <code>DRDAConnThread</code> has been closed.\r
+ *\r
+ * @param thread the closed thread\r
+ */\r
+ void removeThread(DRDAConnThread thread) {\r
+ threadList.remove(thread);\r
+ }\r
+ \r
+ protected Object getShutdownSync() { return shutdownSync; } \r
+ protected boolean getShutdown() { return shutdown; } \r
+\r
+\r
+ public String buildRuntimeInfo(LocalizedResource locallangUtil)\r
+ {\r
+ \r
+ String s = locallangUtil.getTextMessage("DRDA_RuntimeInfoBanner.I")+ "\n";\r
+ int sessionCount = 0;\r
+ s += locallangUtil.getTextMessage("DRDA_RuntimeInfoSessionBanner.I") + "\n";\r
+ for (int i = 0; i < threadList.size(); i++)\r
+ {\r
+ String sessionInfo = ((DRDAConnThread)\r
+ threadList.get(i)).buildRuntimeInfo("",locallangUtil) ;\r
+ if (!sessionInfo.equals(""))\r
+ {\r
+ sessionCount ++;\r
+ s += sessionInfo + "\n";\r
+ }\r
+ }\r
+ int waitingSessions = 0;\r
+ for (int i = 0; i < runQueue.size(); i++)\r
+ {\r
+ s += ((Session)runQueue.get(i)).buildRuntimeInfo("", locallangUtil);\r
+ waitingSessions ++;\r
+ }\r
+ s+= "-------------------------------------------------------------\n";\r
+ s += locallangUtil.getTextMessage("DRDA_RuntimeInfoNumThreads.I") +\r
+ threadList.size() + "\n";\r
+ s += locallangUtil.getTextMessage("DRDA_RuntimeInfoNumActiveSessions.I") +\r
+ sessionCount +"\n";\r
+ s +=locallangUtil.getTextMessage("DRDA_RuntimeInfoNumWaitingSessions.I") +\r
+ + waitingSessions + "\n\n";\r
+\r
+ Runtime rt = Runtime.getRuntime();\r
+ rt.gc();\r
+ long totalmem = rt.totalMemory();\r
+ long freemem = rt.freeMemory();\r
+ s += locallangUtil.getTextMessage("DRDA_RuntimeInfoTotalMemory.I") +\r
+ + totalmem + "\t";\r
+ s += locallangUtil.getTextMessage("DRDA_RuntimeInfoFreeMemory.I") +\r
+ + freemem + "\n\n";\r
+ \r
+ return s;\r
+ }\r
+\r
+\r
+ protected void setClientLocale(String locale)\r
+ {\r
+ clientLocale = locale;\r
+ }\r
+\r
+ /**\r
+ * Retrieve product version information\r
+ * We need to make sure that this method gets the stream and passes it to \r
+ * ProductVersionHolder, because it lives in the Network Server jar\r
+ * and won't be readily available to ProductVersionHolder when running\r
+ * under security manager.\r
+ */\r
+ private ProductVersionHolder getNetProductVersionHolder() throws Exception\r
+ {\r
+ ProductVersionHolder myPVH= null;\r
+ try {\r
+ myPVH = (ProductVersionHolder) AccessController.doPrivileged(\r
+ new PrivilegedExceptionAction() {\r
+ \r
+ public Object run() throws UnknownHostException,IOException\r
+ {\r
+ InputStream versionStream = getClass().getResourceAsStream(ProductGenusNames.NET_INFO);\r
+\r
+ return ProductVersionHolder.getProductVersionHolderFromMyEnv(versionStream);\r
+ }\r
+ });\r
+ \r
+}\r
+ catch(PrivilegedActionException e) {\r
+ Exception e1 = e.getException();\r
+ consolePropertyMessage("DRDA_ProductVersionReadError.S", e1.getMessage()); \r
+ }\r
+ return myPVH;\r
+ }\r
+\r
+ /**\r
+ * This method returns a timestamp to be used in the messages. \r
+ * CheapDateFormatter class, which uses GMT, is used to format timestamps. \r
+ * This is to keep the formatting consistent with Derby boot message since\r
+ * network server messages and the boot message get written to derby.log. \r
+ * \r
+ * @return current timestamp formatted in GMT\r
+ */\r
+ private String getFormattedTimestamp(){\r
+ long currentTime = System.currentTimeMillis();\r
+ return CheapDateFormatter.formatDate(currentTime);\r
+ }\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r