📄 nameserviceclient.java
字号:
/* jcifs smb client library in Java
* Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcifs.netbios;
import java.net.InetAddress;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.UnknownHostException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.HashMap;
import java.util.StringTokenizer;
import jcifs.Config;
import jcifs.util.Hexdump;
import jcifs.util.LogStream;
class NameServiceClient implements Runnable {
static final int DEFAULT_SO_TIMEOUT = 5000;
static final int DEFAULT_RCV_BUF_SIZE = 576;
static final int DEFAULT_SND_BUF_SIZE = 576;
static final int NAME_SERVICE_UDP_PORT = 137;
static final int DEFAULT_RETRY_COUNT = 2;
static final int DEFAULT_RETRY_TIMEOUT = 3000;
static final int RESOLVER_LMHOSTS = 1;
static final int RESOLVER_BCAST = 2;
static final int RESOLVER_WINS = 3;
private static final int SND_BUF_SIZE = Config.getInt( "jcifs.netbios.snd_buf_size", DEFAULT_SND_BUF_SIZE );
private static final int RCV_BUF_SIZE = Config.getInt( "jcifs.netbios.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
private static final int SO_TIMEOUT = Config.getInt( "jcifs.netbios.soTimeout", DEFAULT_SO_TIMEOUT );
private static final int RETRY_COUNT = Config.getInt( "jcifs.netbios.retryCount", DEFAULT_RETRY_COUNT );
private static final int RETRY_TIMEOUT = Config.getInt( "jcifs.netbios.retryTimeout", DEFAULT_RETRY_TIMEOUT);
private static final int LPORT = Config.getInt( "jcifs.netbios.lport", 0 );
private static final InetAddress LADDR = Config.getInetAddress( "jcifs.netbios.laddr", null );
private static final String RO = Config.getProperty( "jcifs.resolveOrder" );
private static LogStream log = LogStream.getInstance();
private final Object LOCK = new Object();
private int lport, closeTimeout;
private byte[] snd_buf, rcv_buf;
private DatagramSocket socket;
private DatagramPacket in, out;
private HashMap responseTable = new HashMap();
private Thread thread;
private int nextNameTrnId = 0;
private int[] resolveOrder;
InetAddress laddr, baddr;
NameServiceClient() {
this( LPORT, LADDR );
}
NameServiceClient( int lport, InetAddress laddr ) {
this.lport = lport;
this.laddr = laddr;
try {
baddr = Config.getInetAddress( "jcifs.netbios.baddr",
InetAddress.getByName( "255.255.255.255" ));
} catch( UnknownHostException uhe ) {
}
snd_buf = new byte[SND_BUF_SIZE];
rcv_buf = new byte[RCV_BUF_SIZE];
out = new DatagramPacket( snd_buf, SND_BUF_SIZE, baddr, NAME_SERVICE_UDP_PORT );
in = new DatagramPacket( rcv_buf, RCV_BUF_SIZE );
if( RO == null || RO.length() == 0 ) {
/* No resolveOrder has been specified, use the
* default which is LMHOSTS,WINS,BCAST,DNS or just
* LMHOSTS,BCAST,DNS if jcifs.netbios.wins has not
* been specified.
*/
if( NbtAddress.getWINSAddress() == null ) {
resolveOrder = new int[2];
resolveOrder[0] = RESOLVER_LMHOSTS;
resolveOrder[1] = RESOLVER_BCAST;
} else {
resolveOrder = new int[3];
resolveOrder[0] = RESOLVER_LMHOSTS;
resolveOrder[1] = RESOLVER_WINS;
resolveOrder[2] = RESOLVER_BCAST;
}
} else {
int[] tmp = new int[3];
StringTokenizer st = new StringTokenizer( RO, "," );
int i = 0;
while( st.hasMoreTokens() ) {
String s = st.nextToken().trim();
if( s.equalsIgnoreCase( "LMHOSTS" )) {
tmp[i++] = RESOLVER_LMHOSTS;
} else if( s.equalsIgnoreCase( "WINS" )) {
if( NbtAddress.getWINSAddress() == null ) {
if( log.level > 1 ) {
log.println( "NetBIOS resolveOrder specifies WINS however the " +
"jcifs.netbios.wins property has not been set" );
}
continue;
}
tmp[i++] = RESOLVER_WINS;
} else if( s.equalsIgnoreCase( "BCAST" )) {
tmp[i++] = RESOLVER_BCAST;
} else if( s.equalsIgnoreCase( "DNS" )) {
; // skip
} else if( log.level > 1 ) {
log.println( "unknown resolver method: " + s );
}
}
resolveOrder = new int[i];
System.arraycopy( tmp, 0, resolveOrder, 0, i );
}
}
int getNextNameTrnId() {
if(( ++nextNameTrnId & 0xFFFF ) == 0 ) {
nextNameTrnId = 1;
}
return nextNameTrnId;
}
void ensureOpen( int timeout ) throws IOException {
closeTimeout = 0;
if( SO_TIMEOUT != 0 ) {
closeTimeout = Math.max( SO_TIMEOUT, timeout );
}
// If socket is still good, the new closeTimeout will
// be ignored; see tryClose comment.
if( socket == null ) {
socket = new DatagramSocket( lport, laddr );
thread = new Thread( this, "JCIFS-NameServiceClient" );
thread.setDaemon( true );
thread.start();
}
}
void tryClose() {
synchronized( LOCK ) {
/* Yes, there is the potential to drop packets
* because we might close the socket during a
* request. However the chances are slim and the
* retry code should ensure the overall request
* is serviced. The alternative complicates things
* more than I think is worth it.
*/
if( socket != null ) {
socket.close();
socket = null;
}
thread = null;
responseTable.clear();
}
}
public void run() {
int nameTrnId;
NameServicePacket response;
try {
while( thread == Thread.currentThread() ) {
in.setLength( RCV_BUF_SIZE );
socket.setSoTimeout( closeTimeout );
socket.receive( in );
if( log.level > 3 )
log.println( "NetBIOS: new data read from socket" );
nameTrnId = NameServicePacket.readNameTrnId( rcv_buf, 0 );
response = (NameServicePacket)responseTable.get( new Integer( nameTrnId ));
if( response == null || response.received ) {
continue;
}
synchronized( response ) {
response.readWireFormat( rcv_buf, 0 );
response.received = true;
if( log.level > 3 ) {
log.println( response );
Hexdump.hexdump( log, rcv_buf, 0, in.getLength() );
}
response.notify();
}
}
} catch( Exception ex ) {
if( log.level > 2 )
ex.printStackTrace( log );
tryClose();
}
}
void send( NameServicePacket request, NameServicePacket response,
int timeout ) throws IOException {
Integer nid = null;
int count = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -