+jcifs-1.1.0 released
+
+The behavior of the firstCalledName/nextCalledName methods has been changed
+to try SMBSERVER* first, then the NetBIOS hostname, then the 0x20 name from
+a Node Status. It is pretty universal now that SMBSERVER* rules the day and
+most servers return failure with the NetBIOS name so this behavior
+eliminates a round trip during session establishment.
+
+The NbtAddress.getByName method has been implemented. This will return the
+full list of RDATA for a name query response. Currently I believe only the
+0x1C domain lookup actually returns multiple results. Note this is
+different from getAllByAddress which does a node status.
+
+The socket code in SmbTransport has been modified to open the socket using
+the transport thread. This permits the caller of the transport to call wait
+for RESPONSE_TIMEOUT. This is great if your application has a tendency to
+try to connect to hosts that do not exist. Normally that would take over a
+minute to timeout. The single threaded SmbCrawler actually performs quite
+well with the right properties set.
+
+An SmbSession.getChallengeForDomain() method has been added that returns an
+NtlmChallenge object containing the byte[] challenge and UniAddress of the
+domain controller from which it came. This method will rotate through a
+list of at most jcifs.netbios.lookupRespLimit addresses and will only
+return a challenge for a responsive server. Unresponsive servers will be
+removed from the list until the jcifs.netbios.cachePolicy has expired. This
+function is used by the NTLM HTTP Filter to locate suitable domain
+controllers.
+
+Because of the above rotation there is a greater potential for transports
+to remain open. Sessions with no activity (this is particularly true with
+the NTLM HTTP Filter which really only touches the session once when the
+user is authenticated) will be logged off after jcifs.smb.client.soTimeout.
+
+A read bug that only manafested itself with a certain EMC server has been
+fixed.
+
Mon Sep 6 20:44:14 EDT 2004
jcifs-1.0.1 released
<project name="jcifs" default="usage" basedir=".">
- <property name="version" value="1.0.1"/>
- <property name="reldate" value="Sep 6, 2004"/>
+ <property name="version" value="1.1.0"/>
+ <property name="reldate" value="Oct 1, 2004"/>
<target name="usage">
<echo>
dependencies: Checks that all class dependencies are met.
compile: Builds the jCIFS classes.
jar: Packages the jCIFS classes into a .jar file.
+ docs: XSLT generated website pages
javadoc: Creates the Javadoc API documentation.
all: Performs all of the above.
<!--copy file="docs/allclasses-frame.html" tofile="docs/api/allclasses-frame.html" overwrite="yes"/-->
</target>
- <target name="all" depends="jar,javadoc"/>
+ <target name="all" depends="jar,docs,javadoc"/>
<target name="clean">
<delete dir="build" quiet="true"/>
--- /dev/null
+import jcifs.netbios.NbtAddress;
+
+public class ListDC {
+
+ public static void main( String argv[] ) throws Exception {
+
+ NbtAddress[] addrs = NbtAddress.getAllByName( argv[0], 0x1C, null, null );
+
+ for( int i = 0; i < addrs.length; i++ ) {
+ System.out.println( addrs[i] );
+ }
+ }
+}
jcifs.smb.client.domain = mydom
jcifs.smb.client.username = miallen
jcifs.smb.client.password = p@ssw0rd
-;jcifs.netbios.wins = 196.22.20.21
-jcifs.netbios.wins = 164.25.87.5
+jcifs.resolveOrder = WINS,DNS
+jcifs.netbios.wins = 196.22.20.21,164.25.87.5
+jcifs.smb.client.signingPreferred = true
;jcifs.util.loglevel = 10
-;jcifs.resolveOrder = WINS,DNS
-;jcifs.netbios.cachePolicy = 3
+;jcifs.netbios.cachePolicy = 30
;jcifs.smb.client.maxBuffers = 20
;jcifs.smb.client.soTimeout = 4000
;jcifs.smb.client.responseTimeout = 15000
;jcifs.smb.client.useUnicode = false
;jcifs.smb.client.disablePlainTextPasswords = false
;jcifs.smb.client.snd_buf_size = 8192
-;jcifs.smb.client.signingPreferred = true
;jcifs.smb.client.useNTSmbs = false
;jcifs.smb.client.useBatching = false
;jcifs.smb.client.listSize = 1200
PROPERTIES=../../miallen.prp
RUN="${JAVA_HOME}/bin/java -cp ${CLASSPATH} -Djcifs.properties=${PROPERTIES}"
-SERVER=rnycwbmallen1
+SERVER=servername
SHARE=pub
WRITE_DIR=test
-SRC_DIR=test/variety
-FILE1=test/variety/Batch2/crash.bmp
+SRC_DIR=test/Junk
+FILE1=test/Junk/tracer/m31_gendler_big.jpg
URL_SHARE=smb://${SERVER}/${SHARE}/
URL_WRITE_DIR=${URL_SHARE}${WRITE_DIR}/
$RUN NodeStatus ${SERVER}
$RUN Put ${URL_WRITE_DIR}Makefile
$RUN Query ${SERVER}
-$RUN RenameTo ${URL_WRITE_DIR}Makefile ${URL_WRITE_DIR}/Makefile.txt
+$RUN RenameTo ${URL_WRITE_DIR}Makefile ${URL_WRITE_DIR}Makefile.txt
$RUN SetAttrs ${URL_WRITE_DIR}Makefile.txt FFFF
$RUN SetTime ${URL_WRITE_DIR}Makefile.txt
$RUN SlowWrite ${URL_WRITE_DIR}SlowWrite.txt
<web-app id='/'>
-<filter filter-name='ntlm' filter-class='jcifs.http.NtlmHttpFilter'>
+<filter
+ filter-name='ntlm'
+ filter-class='jcifs.http.NtlmHttpFilter'>
+
+ <init-param>
+ <param-name>jcifs.netbios.wins</param-name>
+ <param-value>164.152.78.10,164.152.4.22</param-value>
+ </init-param>
+
<init-param>
<param-name>jcifs.smb.client.domain</param-name>
- <param-value>MYDOMAIN</param-value>
+ <param-value>NYC-USERS</param-value>
</init-param>
+
<init-param>
- <param-name>jcifs.netbios.wins</param-name>
- <param-value>164.215.78.56,196.141.101.3</param-value>
+ <param-name>jcifs.smb.client.username</param-name>
+ <param-value>jcifsmachacct</param-value>
</init-param>
<init-param>
+ <param-name>jcifs.smb.client.password</param-name>
+ <param-value>VeRYr@nDoMpa$sW0rD</param-value>
+ </init-param>
+
+ <init-param>
<param-name>jcifs.util.loglevel</param-name>
<param-value>2</param-value>
</init-param>
</filter>
-
-<filter-mapping url-pattern='/*' filter-name='ntlm'/>
+<filter-mapping
+ url-pattern='/*'
+ filter-name='ntlm'/>
</web-app>
import javax.servlet.http.*;
import jcifs.*;
import jcifs.smb.SmbSession;
+import jcifs.smb.NtlmChallenge;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbAuthException;
import jcifs.util.Base64;
if( msg != null && (msg.startsWith( "NTLM " ) ||
(offerBasic && msg.startsWith("Basic ")))) {
- if( loadBalance ) {
- dc = new UniAddress( NbtAddress.getByName( domainController, 0x1C, null ));
- } else {
- dc = UniAddress.getByName( domainController, true );
- }
if (msg.startsWith("NTLM ")) {
- req.getSession();
- byte[] challenge = SmbSession.getChallenge( dc );
+ HttpSession ssn = req.getSession();
+ byte[] challenge;
+
+ if( loadBalance ) {
+ NtlmChallenge chal = (NtlmChallenge)ssn.getAttribute( "NtlmHttpChal" );
+ if( chal == null ) {
+ chal = SmbSession.getChallengeForDomain();
+ ssn.setAttribute( "NtlmHttpChal", chal );
+ }
+ dc = chal.dc;
+ challenge = chal.challenge;
+ } else {
+ dc = UniAddress.getByName( domainController, true );
+ challenge = SmbSession.getChallenge( dc );
+ }
+
if(( ntlm = NtlmSsp.authenticate( req, resp, challenge )) == null ) {
return;
}
+ /* negotiation complete, remove the challenge object */
+ ssn.removeAttribute( "NtlmHttpChal" );
} else {
String auth = new String(Base64.decode(msg.substring(6)),
"US-ASCII");
defaultDomain;
user = (index != -1) ? user.substring(index + 1) : user;
ntlm = new NtlmPasswordAuthentication(domain, user, password);
+ dc = UniAddress.getByName( domainController, true );
}
try {
class NameQueryResponse extends NameServicePacket {
- NbtAddress addrEntry;
-
NameQueryResponse() {
recordName = new Name();
}
int nodeType = ( src[srcIndex] & 0x60 ) >> 5;
srcIndex += 2;
int address = readInt4( src, srcIndex );
- addrEntry = new NbtAddress( recordName, address, groupName, nodeType );
+ if( address != 0 ) {
+ addrEntry[addrIndex] = new NbtAddress( recordName, address, groupName, nodeType );
+ } else {
+ addrEntry[addrIndex] = null;
+ }
+
return 6;
}
public String toString() {
}
}
+ NbtAddress[] getAllByName( Name name, InetAddress addr )
+ throws UnknownHostException {
+ NameQueryRequest request = new NameQueryRequest( name );
+ NameQueryResponse response = new NameQueryResponse();
+
+ request.addr = addr != null ? addr : NbtAddress.getWINSAddress();
+ request.isBroadcast = false;
+
+ try {
+ send( request, response, RETRY_TIMEOUT );
+ } catch( IOException ioe ) {
+ if( log.level > 1 )
+ ioe.printStackTrace( log );
+ throw new UnknownHostException( name.name );
+ }
+
+ return response.addrEntry;
+ }
NbtAddress getByName( Name name, InetAddress addr )
throws UnknownHostException {
int n;
}
if( response.received && response.resultCode == 0 ) {
- response.addrEntry.hostName.srcHashCode = addr.hashCode();
- return response.addrEntry;
+ response.addrEntry[0].hostName.srcHashCode = addr.hashCode();
+ return response.addrEntry[0];
}
} while( --n > 0 && request.isBroadcast );
* Lmhosts, WINS, or BCAST. Otherwise a failed query from say WINS would
* get pulled out of the cache for a BCAST on the same name.
*/
- response.addrEntry.hostName.srcHashCode =
+ response.addrEntry[0].hostName.srcHashCode =
request.addr.hashCode();
- return response.addrEntry;
+ return response.addrEntry[0];
} else if( resolveOrder[i] == RESOLVER_WINS ) {
/* If WINS reports negative, no point in retry
*/
abstract class NameServicePacket {
- private static final int LOOKUP_RESP_LIMIT = jcifs.Config.getInt( "jcifs.netbios.lookupRespLimit", 5 );
-
- private static int addrIndex = 0;
-
// opcode
static final int QUERY = 0;
static final int WACK = 7;
return readInt2( src, srcIndex );
}
+ int addrIndex;
+ NbtAddress[] addrEntry;
+
int nameTrnId;
int opCode,
rDataLength = readInt2( src, srcIndex );
srcIndex += 2;
+ addrEntry = new NbtAddress[rDataLength / 6];
end = srcIndex + rDataLength;
- for( int i = 0; srcIndex < end; i++ ) {
+ for( addrIndex = 0; srcIndex < end; addrIndex++ ) {
srcIndex += readRDataWireFormat( src, srcIndex );
- if( i == addrIndex ) {
- addrIndex++;
- if( addrIndex == LOOKUP_RESP_LIMIT ) {
- addrIndex = 0;
- }
- return end - start;
- }
}
- addrIndex = 0;
return srcIndex - start;
}
}
}
+ public static NbtAddress[] getAllByName( String host,
+ int type,
+ String scope,
+ InetAddress svr )
+ throws UnknownHostException {
+ return CLIENT.getAllByName( new Name( host, type, scope ), svr );
+ }
+
/**
* Retrieve all addresses of a host by it's address. NetBIOS hosts can
* have many names for a given IP address. The name and IP address make the
*/
public String firstCalledName() {
-
- calledName = hostName.name;
-
- if( Character.isDigit( calledName.charAt( 0 ))) {
- int i, len, dots;
- char[] data;
-
- i = dots = 0; /* quick IP address validation */
- len = calledName.length();
- data = calledName.toCharArray();
- while( i < len && Character.isDigit( data[i++] )) {
- if( i == len && dots == 3 ) {
- // probably an IP address
- calledName = SMBSERVER_NAME;
- break;
- }
- if( i < len && data[i] == '.' ) {
- dots++;
- i++;
- }
- }
- } else if( hostName.hexCode == 0x1D ) {
- calledName = SMBSERVER_NAME;
- }
-
+ calledName = SMBSERVER_NAME;
return calledName;
}
public String nextCalledName() {
- if( calledName == hostName.name ) {
- calledName = SMBSERVER_NAME;
- } else if( calledName == SMBSERVER_NAME ) {
+ if( calledName == SMBSERVER_NAME ) {
+ calledName = hostName.name;
+ } else if( calledName == hostName.name ) {
NbtAddress[] addrs;
try {
protected String wildcard;
protected int attributes;
+/* This filter can be considerably more efficient than other file filters
+ * as the specifed wildcard and attributes are passed to the server for
+ * filtering there.
+ */
public DosFileFilter( String wildcard, int attributes ) {
this.wildcard = wildcard;
this.attributes = attributes;
}
- /**
- * This always returns <tt>true</tt> as the wildcard and
- * attributes members are passed to the server which uses them to
- * filter on behalf of the client. Sub-classes might overload this
- * method to further filter the list however.
- */
+/* This returns true if the file's attributes contain any of the attributes
+ * specified for this filter. The wildcard has no influence on this
+ * method as the server should have performed that filtering already. The
+ * attributes are asserted here only because server file systems may not
+ * support filtering by all attributes (e.g. even though ATTR_DIRECTORY was
+ * specified the server may still return objects that are not directories).
+ */
public boolean accept( SmbFile file ) throws SmbException {
- return true;
+ return (file.getAttributes() & attributes) != 0;
}
}
--- /dev/null
+/* jcifs smb client library in Java
+ * Copyright (C) 2004 "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.smb;
+
+import jcifs.UniAddress;
+import jcifs.util.Hexdump;
+
+public final class NtlmChallenge {
+
+ public byte[] challenge;
+ public UniAddress dc;
+
+ NtlmChallenge( byte[] challenge, UniAddress dc ) {
+ this.challenge = challenge;
+ this.dc = dc;
+ }
+
+ public String toString() {
+ return "NtlmChallenge[challenge=0x" +
+ Hexdump.toHexString( challenge, 0, challenge.length * 2 ) +
+ ",dc=" + dc.toString() + "]";
+ }
+}
int pad = dataOffset - ( HEADER_LENGTH + 3 + wordCount * 2 );
in.read( buffer, bufferIndex, pad ); /* needed for signing */
in.read( b, off, dataLength );
- return dataLength;
+ return pad + dataLength;
}
public String toString() {
return new String( "SmbComReadAndXResponse[" +
import java.net.UnknownHostException;
import jcifs.Config;
import jcifs.UniAddress;
+import jcifs.netbios.NbtAddress;
/**
* The class represents a user's session established with an SMB/CIFS
public final class SmbSession {
private static final String LOGON_SHARE = Config.getProperty( "jcifs.smb.client.logonShare", "IPC$" );
+ private static final int LOOKUP_RESP_LIMIT = jcifs.Config.getInt( "jcifs.netbios.lookupRespLimit", 5 );
+ private static final String DOMAIN = Config.getProperty("jcifs.smb.client.domain", null);
+ private static final String USERNAME = Config.getProperty("jcifs.smb.client.username", null);
+ private static final int DEFAULT_CACHE_POLICY = 30;
+ private static final int CACHE_POLICY = Config.getInt( "jcifs.netbios.cachePolicy", DEFAULT_CACHE_POLICY );
+
+ static long dc_list_expiration;
+ static NbtAddress[] dc_list = null;
+ static int dc_list_index; /* always less than dc_list_range */
+ static int dc_list_range = 1; /* always less than LOOKUP_RESP_LIMIT */
+
+ static void incr_dc_list_range() {
+ if( dc_list_range < LOOKUP_RESP_LIMIT &&
+ dc_list_range < dc_list.length ) {
+ dc_list_range++;
+ }
+ }
+ public static NtlmChallenge getChallengeForDomain()
+ throws SmbException, UnknownHostException {
+ int starting_index;
+
+ if( DOMAIN == null ) {
+ throw new SmbException( "A domain was not specified" );
+ }
+synchronized( DOMAIN ) {
+ if( dc_list_expiration < System.currentTimeMillis() ) {
+ dc_list = NbtAddress.getAllByName( DOMAIN, 0x1C, null, null );
+ dc_list_expiration = System.currentTimeMillis() + CACHE_POLICY * 1000L;
+ if( dc_list_range > 1 ) {
+ dc_list_range /= 2; /* shrink dc_list_range */
+ }
+ }
+
+ starting_index = dc_list_index;
+ do {
+ if( dc_list_index == dc_list_range ) {
+ dc_list_index = 0;
+ }
+ NbtAddress addr = dc_list[dc_list_index];
+ if( addr != null ) {
+ try {
+ UniAddress dc = new UniAddress( addr );
+ SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 );
+ if( USERNAME == null ) {
+ if( SmbTransport.log.level > 1 )
+ SmbTransport.log.println( "Default credentials (jcifs.smb.client.username/password) not specified. SMB signing may not work propertly. Skipping DC interrogation." );
+ trans.negotiate();
+ } else {
+ trans.getSmbSession( NtlmPasswordAuthentication.DEFAULT ).getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
+ }
+ if( trans.sessions.size() > (trans.SSN_LIMIT / 10)) {
+ incr_dc_list_range();
+ }
+ dc_list_index++;
+ return new NtlmChallenge( trans.server.encryptionKey, dc );
+ } catch( SmbException se ) {
+ if( SmbTransport.log.level > 1 )
+ SmbTransport.log.println( "Failed validate DC: " + addr + ": " + se.getMessage() );
+ }
+ dc_list[dc_list_index] = null; /* dc no good */
+ incr_dc_list_range();
+ }
+ dc_list_index++;
+ } while( dc_list_index != starting_index );
+}
+
+ throw new UnknownHostException( "Failed to negotiate with a suitable domain controller for " + DOMAIN );
+ }
+
public static byte[] getChallenge( UniAddress dc )
throws SmbException, UnknownHostException {
SmbTransport transport = SmbTransport.NULL_TRANSPORT;
NtlmPasswordAuthentication auth;
+ long expiration;
SmbSession( UniAddress address, int port,
InetAddress localAddr, int localPort,
void sessionSetup( ServerMessageBlock andx,
ServerMessageBlock andxResponse ) throws SmbException {
+ expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT;
+
synchronized( transport() ) {
if( sessionSetup ) {
return;
private static final InetAddress LADDR = Config.getInetAddress( "jcifs.smb.client.laddr", null );
private static final int LPORT = Config.getInt( "jcifs.smb.client.lport", 0 );
- private static final int SSN_LIMIT = Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT );
private static final int MAX_MPX_COUNT = Config.getInt( "jcifs.smb.client.maxMpxCount", DEFAULT_MAX_MPX_COUNT );
private static final int SND_BUF_SIZE = Config.getInt( "jcifs.smb.client.snd_buf_size", DEFAULT_SND_BUF_SIZE );
private static final int RCV_BUF_SIZE = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
ServerMessageBlock.CAP_DFS;
private static final int FLAGS2 = Config.getInt( "jcifs.smb.client.flags2", DEFAULT_FLAGS2 );
private static final int CAPABILITIES = Config.getInt( "jcifs.smb.client.capabilities", DEFAULT_CAPABILITIES );
- private static final int SO_TIMEOUT = Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT );
private static final boolean TCP_NODELAY = Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false );
private static final int RESPONSE_TIMEOUT =
Config.getInt( "jcifs.smb.client.responseTimeout", DEFAULT_RESPONSE_TIMEOUT );
private static final int PUSHBACK_BUF_SIZE = 64;
private static final int MID_OFFSET = 30;
private static final int FLAGS_RESPONSE = 0x80;
- private static final int ST_GROUND = 0;
- private static final int ST_NEGOTIATING = 1;
private static final LinkedList CONNECTIONS = new LinkedList();
private static final int MAGIC[] = { 0xFF, 'S', 'M', 'B' };
+ private static final int ST_GROUND = 0;
+ private static final int ST_NEGOTIATING = 1;
+ private static final int ST_NEGOTIATED = 2;
+
private static byte[] snd_buf = new byte[0xFFFF];
private static byte[] rcv_buf = new byte[0xFFFF];
+ private int state;
private NbtSocket socket;
private HashMap responseTable;
private InputStream in;
private Object outLock;
private UniAddress address;
private int port;
- private LinkedList sessions;
private LinkedList referrals = new LinkedList();
- private int state;
private Mid[] mids = new Mid[MAX_MPX_COUNT];
private short mid_next;
+ private IOException socketException;
+ private long sessionExpiration = System.currentTimeMillis() + SO_TIMEOUT;
+ static final int SSN_LIMIT =
+ Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT );
+ static final int SO_TIMEOUT =
+ Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT );
static final String NATIVE_OS =
Config.getProperty( "jcifs.smb.client.nativeOs", System.getProperty( "os.name" ));
static final String NATIVE_LANMAN =
String tconHostName;
ServerData server;
SigningDigest digest = null;
+ LinkedList sessions;
static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
return getSmbTransport( address, port, LADDR, LPORT );
return ssn;
}
}
+
+ /* close old sessions */
+ long now = System.currentTimeMillis();
+ if( sessionExpiration < now ) {
+ sessionExpiration = now + SO_TIMEOUT;
+ iter = sessions.listIterator();
+ while( iter.hasNext() ) {
+ ssn = (SmbSession)iter.next();
+ if( ssn.expiration < now ) {
+ ssn.logoff( false );
+ sessions.remove( ssn );
+ }
+ }
+ }
+
ssn = new SmbSession( address, port, localAddr, localPort, auth );
ssn.transport = this;
sessions.add( ssn );
auth != NtlmPasswordAuthentication.NULL &&
NtlmPasswordAuthentication.NULL.equals( auth ) == false;
}
- void ensureOpen() throws IOException {
+ void tryClose( boolean inError ) {
+ SmbSession ssn;
+
if( socket == null ) {
+ inError = true;
+ }
+
+ ListIterator iter = sessions.listIterator();
+ while( iter.hasNext() ) {
+ ssn = (SmbSession)iter.next();
+ ssn.logoff( inError );
+ }
+ if( socket != null ) {
+ try {
+ socket.close();
+ } catch( IOException ioe ) {
+ }
+ }
+ digest = null;
+ in = null;
+ out = null;
+ socket = null;
+ thread = null;
+ responseTable.clear();
+ referrals.clear();
+ sessions.clear();
+ synchronized( CONNECTIONS ) {
+ CONNECTIONS.remove( this );
+ }
+ state = ST_GROUND;
+ }
+ void start() throws SmbException {
+ try {
+ thread = new Thread( this, "JCIFS-SmbTransport" );
+ thread.setDaemon( true );
+ thread.start();
+
+ wait( RESPONSE_TIMEOUT ); /* wait for the thread to be started and socket opened */
+
+ if( socket == null ) { /* failed to open socket for some reason */
+ tryClose( true );
+ throw new SmbException( "Timeout trying to open socket (probably no ACK to SYN) for address", socketException );
+ }
+ } catch( InterruptedException ie ) {
+ tryClose( true );
+ throw new SmbException( "Interrupted opening socket", ie );
+ }
+ }
+ public void run() {
+ Mid mid = new Mid();
+ int i, m, nbtlen;
+ ServerMessageBlock response;
+
+ try {
Object obj;
NbtAddress naddr;
String calledName;
do {
try {
socket = new NbtSocket( naddr, calledName, port, localAddr, localPort );
+ if( TCP_NODELAY ) {
+ socket.setTcpNoDelay( true );
+ }
+ socket.setSoTimeout( SO_TIMEOUT );
+ in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE );
+ out = socket.getOutputStream();
break;
} catch( NbtException ne ) {
if( ne.errorClass == NbtException.ERR_SSN_SRVC &&
}
} while(( calledName = address.nextCalledName()) != null );
- if( calledName == null ) {
+ if( socket == null ) {
throw new IOException( "Failed to establish session with " + address );
}
} else {
tconHostName = calledName;
}
-
- if( TCP_NODELAY ) {
- socket.setTcpNoDelay( true );
- }
- in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE );
- out = socket.getOutputStream();
- thread = new Thread( this, "JCIFS-SmbTransport" );
- thread.setDaemon( true );
- thread.start();
- }
- }
- void tryClose( boolean inError ) {
- SmbSession ssn;
-
- if( socket == null ) {
- inError = true;
- }
-
- ListIterator iter = sessions.listIterator();
- while( iter.hasNext() ) {
- ssn = (SmbSession)iter.next();
- ssn.logoff( inError );
- }
- if( socket != null ) {
- try {
- socket.close();
- } catch( IOException ioe ) {
+ } catch( IOException ioe ) {
+ socketException = ioe;
+ if( log.level > 1 )
+ ioe.printStackTrace( log );
+ return;
+ } finally {
+ synchronized( this ) {
+ notifyAll();
}
}
- digest = null;
- in = null;
- out = null;
- socket = null;
- thread = null;
- responseTable.clear();
- referrals.clear();
- sessions.clear();
- synchronized( CONNECTIONS ) {
- CONNECTIONS.remove( this );
- }
- state = ST_GROUND;
- }
- public void run() {
- Mid mid = new Mid();
- int i, m, nbtlen;
- ServerMessageBlock response;
while( thread == Thread.currentThread() ) {
try {
- socket.setSoTimeout( SO_TIMEOUT );
-
m = 0;
while( m < 4 ) {
if(( i = in.read() ) < 0 ) {
response = (ServerMessageBlock)responseTable.get( mid );
if( response == null ) {
- if( log.level > 1 ) {
+ if( log.level > 2 ) {
log.println( "no handler for mid=" + mid.mid +
", purging session message: " + address );
}
}
}
response.notify();
- } else {
- ensureOpen();
}
} else {
response.readWireFormat( in, rcv_buf, 0 );
ServerMessageBlock response ) throws SmbException {
Mid mid = null;
- if (state == ST_GROUND) {
+ if( request.command != request.SMB_COM_NEGOTIATE )
negotiate();
- }
request.flags2 |= flags2;
request.useUnicode = useUnicode;
try {
mid = aquireMid();
request.mid = mid.mid;
- ensureOpen();
synchronized( snd_buf ) {
request.digest = digest;
request.response = null;
mid = aquireMid();
request.mid = mid.mid;
responseTable.put( mid, response );
- ensureOpen();
synchronized( snd_buf ) {
if( digest != null ) {
request.digest = digest;
mid = aquireMid();
request.mid = mid.mid;
responseTable.put( mid, interimResponse );
- ensureOpen();
synchronized(snd_buf) {
request.digest = digest;
request.response = response;
request.mid = mid.mid;
responseTable.put( mid, response );
do {
- ensureOpen();
synchronized( snd_buf ) {
request.digest = digest;
request.response = response;
}
synchronized void negotiate() throws SmbException {
+ if( state == ST_GROUND ) {
+ state = ST_NEGOTIATING;
+ } else {
+ while( state != ST_NEGOTIATED ) {
+ try {
+ wait();
+ } catch( InterruptedException ie ) {
+ tryClose( true );
+ throw new SmbException( "Interrupted opening socket", ie );
+ }
+ }
+ return;
+ }
+
+ start(); /* start the transport thread (which opens the socket) */
+
if( this == NULL_TRANSPORT ) {
throw new RuntimeException( "Null transport cannot be used" );
}
- if( state >= ST_NEGOTIATING ) {
- return;
- }
- state = ST_NEGOTIATING;
if( log.level > 2 )
log.println( "requesting negotiation with " + address );
flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
}
}
+
+ state = ST_NEGOTIATED;
}
public String toString() {
String ret = "SmbTransport[address=" + address;