001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
002: // Copyright (C) 2004 The jTDS Project
003: //
004: // This library is free software; you can redistribute it and/or
005: // modify it under the terms of the GNU Lesser General Public
006: // License as published by the Free Software Foundation; either
007: // version 2.1 of the License, or (at your option) any later version.
008: //
009: // This library is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: // Lesser General Public License for more details.
013: //
014: // You should have received a copy of the GNU Lesser General Public
015: // License along with this library; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: //
018: package net.sourceforge.jtds.jdbc;
019:
020: import java.io.InterruptedIOException;
021: import java.sql.SQLException;
022: import java.net.*;
023:
024: import net.sourceforge.jtds.util.Logger;
025:
026: /**
027: * This class communicates with SQL Server 2k to determine what ports its
028: * instances are listening to. It does this by sending a UDP packet with the
029: * byte 0x02 in it, and parsing the response.
030: * <p>
031: * An example of the return packet format is as follows:
032: * <pre>
033: * < 00000000 05 ea 00 53 65 72 76 65 72 4e 61 6d 65 3b 42 52 # ...ServerName;BR
034: * < 00000010 49 4e 4b 4c 45 59 3b 49 6e 73 74 61 6e 63 65 4e # INKLEY;InstanceN
035: * < 00000020 61 6d 65 3b 4d 53 53 51 4c 53 45 52 56 45 52 3b # ame;MSSQLSERVER;
036: * < 00000030 49 73 43 6c 75 73 74 65 72 65 64 3b 4e 6f 3b 56 # IsClustered;No;V
037: * < 00000040 65 72 73 69 6f 6e 3b 38 2e 30 30 2e 31 39 34 3b # ersion;8.00.194;
038: * < 00000050 74 63 70 3b 31 34 33 33 3b 6e 70 3b 5c 5c 42 52 # tcp;1433;np;\\BR
039: * < 00000060 49 4e 4b 4c 45 59 5c 70 69 70 65 5c 73 71 6c 5c # INKLEY\pipe\sql\
040: * < 00000070 71 75 65 72 79 3b 3b 53 65 72 76 65 72 4e 61 6d # query;;ServerNam
041: * < 00000080 65 3b 42 52 49 4e 4b 4c 45 59 3b 49 6e 73 74 61 # e;BRINKLEY;Insta
042: * < 00000090 6e 63 65 4e 61 6d 65 3b 44 4f 47 3b 49 73 43 6c # nceName;DOG;IsCl
043: * < 000000a0 75 73 74 65 72 65 64 3b 4e 6f 3b 56 65 72 73 69 # ustered;No;Versi
044: * < 000000b0 6f 6e 3b 38 2e 30 30 2e 31 39 34 3b 74 63 70 3b # on;8.00.194;tcp;
045: * < 000000c0 33 35 34 36 3b 6e 70 3b 5c 5c 42 52 49 4e 4b 4c # 3546;np;\\BRINKL
046: * < 000000d0 45 59 5c 70 69 70 65 5c 4d 53 53 51 4c 24 44 4f # EY\pipe\MSSQL$DO
047: * < 000000e0 47 5c 73 71 6c 5c 71 75 65 72 79 3b 3b # G\sql\query;;
048: * </pre>
049: *
050: * @author Matt Brinkley
051: * @version $Id: MSSqlServerInfo.java,v 1.8 2005/04/20 16:49:22 alin_sinpalean Exp $
052: */
053: public class MSSqlServerInfo {
054: private int numRetries = 3;
055: private int timeout = 2000;
056: private String[] serverInfoStrings;
057:
058: public MSSqlServerInfo(String host) throws SQLException {
059: try {
060: InetAddress addr = InetAddress.getByName(host);
061: DatagramSocket socket = new DatagramSocket();
062: byte[] msg = new byte[] { 0x02 };
063: DatagramPacket p = new DatagramPacket(msg, msg.length,
064: addr, 1434);
065:
066: socket.send(p);
067:
068: byte[] buf = new byte[4096];
069:
070: p = new DatagramPacket(buf, buf.length);
071: socket.setSoTimeout(timeout);
072:
073: for (int i = 0; i < numRetries; i++) {
074: try {
075: socket.receive(p);
076: String infoString = extractString(buf, p
077: .getLength());
078: serverInfoStrings = split(infoString, ';');
079:
080: return;
081: } catch (InterruptedIOException toEx) {
082: if (Logger.isActive()) {
083: Logger.logException(toEx);
084: }
085: }
086: }
087: } catch (Exception e) {
088: if (Logger.isActive()) {
089: Logger.logException(e);
090: }
091: }
092:
093: throw new SQLException(Messages.get("error.msinfo.badinfo",
094: host), "HY000");
095: }
096:
097: /**
098: * Call getInfo() before calling this method. It parses the info string
099: * returned from SQL Server and looks for the port for the given named
100: * instance. If it can't be found, or if getInfo() hadsn't been called,
101: * it returns -1.
102: *
103: * @param instanceName
104: * @return port the given instance is listening on, or -1 if it can't be
105: * found.
106: */
107: public int getPortForInstance(String instanceName)
108: throws SQLException {
109: if (serverInfoStrings == null) {
110: return -1;
111: }
112:
113: // NOTE: default instance is called MSSQLSERVER
114: if (instanceName == null || instanceName.length() == 0) {
115: instanceName = "MSSQLSERVER";
116: }
117:
118: String curInstance = null;
119: String curPort = null;
120:
121: for (int index = 0; index < serverInfoStrings.length; index++) {
122: if (serverInfoStrings[index].length() == 0) {
123: curInstance = null;
124: curPort = null;
125: } else {
126: String key = serverInfoStrings[index];
127: String value = "";
128:
129: index++;
130:
131: if (index < serverInfoStrings.length) {
132: value = serverInfoStrings[index];
133: }
134:
135: if ("InstanceName".equals(key)) {
136: curInstance = value;
137: }
138:
139: if ("tcp".equals(key)) {
140: curPort = value;
141: }
142:
143: if (curInstance != null && curPort != null
144: && curInstance.equalsIgnoreCase(instanceName)) {
145:
146: try {
147: return Integer.parseInt(curPort);
148: } catch (NumberFormatException e) {
149: throw new SQLException(Messages.get(
150: "error.msinfo.badport", instanceName),
151: "HY000");
152: }
153: }
154: }
155: }
156:
157: // didn't find it...
158: return -1;
159: }
160:
161: private static final String extractString(byte[] buf, int len) {
162: // the first three bytes are unknown; after that, it should be a narrow string...
163: final int headerLength = 3;
164:
165: return new String(buf, headerLength, len - headerLength);
166: }
167:
168: public static String[] split(String s, int ch) {
169: int size = 0;
170: for (int pos = 0; pos != -1; pos = s.indexOf(ch, pos + 1), size++)
171: ;
172:
173: String res[] = new String[size];
174: int i = 0;
175: int p1 = 0;
176: int p2 = s.indexOf(ch);
177:
178: do {
179: res[i++] = s.substring(p1, p2 == -1 ? s.length() : p2);
180: p1 = p2 + 1;
181: p2 = s.indexOf(ch, p1);
182: } while (p1 != 0);
183:
184: return res;
185: }
186: }
|