KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > netbios > NetBIOSSession


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.netbios;
18
19 import java.io.DataInputStream JavaDoc;
20 import java.io.DataOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.net.DatagramPacket JavaDoc;
23 import java.net.DatagramSocket JavaDoc;
24 import java.net.InetAddress JavaDoc;
25 import java.net.Socket JavaDoc;
26 import java.net.SocketException JavaDoc;
27 import java.net.UnknownHostException JavaDoc;
28 import java.util.Vector JavaDoc;
29
30 import org.alfresco.filesys.smb.NetworkSession;
31 import org.alfresco.filesys.util.DataPacker;
32 import org.alfresco.filesys.util.HexDump;
33 import org.alfresco.filesys.util.StringList;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 /**
38  * NetBIOS session class.
39  */

40 public final class NetBIOSSession implements NetworkSession
41 {
42     private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.netbios");
43
44     // Constants
45
//
46
// Caller name template
47

48     public static final int MaxCallerNameTemplateLength = 8;
49     public static final char SessionIdChar = '#';
50     public static final char JVMIdChar = '@';
51     public static final String JavaDoc ValidTemplateChars = "@#_";
52
53     // Default find name buffer size
54

55     private static final int FindNameBufferSize = 2048;
56
57     // Default socket timeout, in milliseconds
58

59     private static int _defTimeout = RFCNetBIOSProtocol.TMO;
60
61     // Remote socket to connect to, default is 139.
62

63     private int m_remotePort;
64
65     // Socket used to connect and read/write to remote host
66

67     private Socket JavaDoc m_nbSocket;
68
69     // Input and output data streams, from the socket network connection
70

71     private DataInputStream JavaDoc m_nbIn;
72     private DataOutputStream JavaDoc m_nbOut;
73
74     // Send/receive timeout, in milliseconds
75

76     private int m_tmo = _defTimeout;
77
78     // Local and remote name types
79

80     private char m_locNameType = NetBIOSName.FileServer;
81     private char m_remNameType = NetBIOSName.FileServer;
82
83     // Unique session identifier, used to generate a unique caller name when opening a new session
84

85     private static int m_sessIdx = 0;
86
87     // Unique JVM id, used to generate a unique caller name when multiple JVMs may be running on the
88
// same
89
// host
90

91     private static int m_jvmIdx = 0;
92
93     // Caller name template string. The template is used to create a unique caller name when opening
94
// a new session.
95
// The template is appended to the local host name, which may be truncated to allow room for the
96
// template to be
97
// appended and still be within the 16 character NetBIOS name limit.
98
//
99
// The caller name generation replaces '#' characters with a zero padded session index as a hex
100
// value and '@'
101
// characters with a zero padded JVM index. Multiple '#' and/or '@' characters can be specified
102
// to indicate the
103
// field width. Any other characters in the template are passed through to the final caller name
104
// string.
105
//
106
// The maximum template string length is 8 characters to allow for at least 8 characters from
107
// the host name.
108

109     private static String JavaDoc m_callerTemplate = "_##";
110
111     // Truncated host name, caller name generation appends the caller template result to this string
112

113     private static String JavaDoc m_localNamePart;
114
115     // Transaction identifier, used for datagrams
116

117     private static short m_tranIdx = 1;
118
119     // RFC NetBIOS name service datagram socket
120

121     private static DatagramSocket JavaDoc m_dgramSock = null;
122
123     // Debug enable flag
124

125     private static boolean m_debug = false;
126
127     // Subnet mask, required for broadcast name lookup requests
128

129     private static String JavaDoc m_subnetMask = null;
130
131     // WINS server address
132

133     private static InetAddress JavaDoc m_winsServer;
134
135     // Name lookup types
136

137     public static final int DNSOnly = 1;
138     public static final int WINSOnly = 2;
139     public static final int WINSAndDNS = 3;
140
141     // Flag to control whether name lookups use WINS/NetBIOS lookup or DNS
142

143     private static int m_lookupType = WINSAndDNS;
144
145     // NetBIOS name lookup timeout value.
146

147     private static int m_lookupTmo = 500;
148
149     // Flag to control use of the '*SMBSERVER' name when connecting to a file server
150

151     private static boolean m_useWildcardFileServer = true;
152
153     /**
154      * NetBIOS session class constructor. Create a NetBIOS session with the default socket number
155      * and no current network connection.
156      */

157     public NetBIOSSession()
158     {
159         m_remotePort = RFCNetBIOSProtocol.PORT;
160         m_nbSocket = null;
161     }
162
163     /**
164      * NetBIOS session class constructor
165      *
166      * @param tmo Send/receive timeout value in milliseconds
167      */

168     public NetBIOSSession(int tmo)
169     {
170         m_tmo = tmo;
171         m_remotePort = RFCNetBIOSProtocol.PORT;
172         m_nbSocket = null;
173     }
174
175     /**
176      * NetBIOS session class constructor
177      *
178      * @param tmo Send/receive timeout value in milliseconds
179      * @param port Remote port to connect to
180      */

181     public NetBIOSSession(int tmo, int port)
182     {
183         m_tmo = tmo;
184         m_remotePort = port;
185         m_nbSocket = null;
186     }
187
188     /**
189      * Return the protocol name
190      *
191      * @return String
192      */

193     public final String JavaDoc getProtocolName()
194     {
195         return "TCP/IP NetBIOS";
196     }
197
198     /**
199      * Determine if the session is connected to a remote host
200      *
201      * @return boolean
202      */

203     public final boolean isConnected()
204     {
205
206         // Check if the socket is valid
207

208         if (m_nbSocket == null)
209             return false;
210         return true;
211     }
212
213     /**
214      * Check if there is data available on this network session
215      *
216      * @return boolean
217      * @exception IOException
218      */

219     public final boolean hasData() throws IOException JavaDoc
220     {
221
222         // Check if the connection is active
223

224         if (m_nbSocket == null || m_nbIn == null)
225             return false;
226
227         // Check if there is data available
228

229         return m_nbIn.available() > 0 ? true : false;
230     }
231
232     /**
233      * Convert a host name string into RFC NetBIOS format.
234      *
235      * @param hostName Host name to be converted.
236      * @return Converted host name string.
237      */

238     public static String JavaDoc ConvertName(String JavaDoc hostName)
239     {
240         return ConvertName(hostName, NetBIOSName.FileServer);
241     }
242
243     /**
244      * Convert a host name string into RFC NetBIOS format.
245      *
246      * @param hostName Host name to be converted.
247      * @param nameType NetBIOS name type, added as the 16th byte of the name before conversion.
248      * @return Converted host name string.
249      */

250     public static String JavaDoc ConvertName(String JavaDoc hostName, char nameType)
251     {
252
253         // Build the name string with the name type, make sure that the host
254
// name is uppercase.
255

256         StringBuffer JavaDoc hName = new StringBuffer JavaDoc(hostName.toUpperCase());
257
258         if (hName.length() > 15)
259             hName.setLength(15);
260
261         // Space pad the name then add the NetBIOS name type
262

263         while (hName.length() < 15)
264             hName.append(' ');
265         hName.append(nameType);
266
267         // Convert the NetBIOS name string to the RFC NetBIOS name format
268

269         String JavaDoc convstr = new String JavaDoc("ABCDEFGHIJKLMNOP");
270         StringBuffer JavaDoc nameBuf = new StringBuffer JavaDoc(32);
271
272         int idx = 0;
273
274         while (idx < hName.length())
275         {
276
277             // Get the current character from the host name string
278

279             char ch = hName.charAt(idx++);
280
281             if (ch == ' ')
282             {
283
284                 // Append an encoded <SPACE> character
285

286                 nameBuf.append("CA");
287             }
288             else
289             {
290
291                 // Append octet for the current character
292

293                 nameBuf.append(convstr.charAt((int) ch / 16));
294                 nameBuf.append(convstr.charAt((int) ch % 16));
295             }
296
297         } // end while
298

299         // Return the encoded string
300

301         return nameBuf.toString();
302     }
303
304     /**
305      * Convert an encoded NetBIOS name to a normal name string
306      *
307      * @param buf Buffer that contains the NetBIOS encoded name
308      * @param off Offset that the name starts within the buffer
309      * @return Normal NetBIOS name string
310      */

311     public static String JavaDoc DecodeName(byte[] buf, int off)
312     {
313
314         // Convert the RFC NetBIOS name string to a normal NetBIOS name string
315

316         String JavaDoc convstr = new String JavaDoc("ABCDEFGHIJKLMNOP");
317         StringBuffer JavaDoc nameBuf = new StringBuffer JavaDoc(16);
318
319         int idx = 0;
320         char ch1, ch2;
321
322         while (idx < 32)
323         {
324
325             // Get the current encoded character pair from the encoded name string
326

327             ch1 = (char) buf[off + idx];
328             ch2 = (char) buf[off + idx + 1];
329
330             if (ch1 == 'C' && ch2 == 'A')
331             {
332
333                 // Append a <SPACE> character
334

335                 nameBuf.append(' ');
336             }
337             else
338             {
339
340                 // Convert back to a character code
341

342                 int val = convstr.indexOf(ch1) << 4;
343                 val += convstr.indexOf(ch2);
344
345                 // Append the current character to the decoded name
346

347                 nameBuf.append((char) (val & 0xFF));
348             }
349
350             // Update the encoded string index
351

352             idx += 2;
353
354         } // end while
355

356         // Return the decoded string
357

358         return nameBuf.toString();
359     }
360
361     /**
362      * Convert an encoded NetBIOS name to a normal name string
363      *
364      * @param encnam RFC NetBIOS encoded name
365      * @return Normal NetBIOS name string
366      */

367
368     public static String JavaDoc DecodeName(String JavaDoc encnam)
369     {
370
371         // Check if the encoded name string is valid, must be 32 characters
372

373         if (encnam == null || encnam.length() != 32)
374             return "";
375
376         // Convert the RFC NetBIOS name string to a normal NetBIOS name string
377

378         String JavaDoc convstr = new String JavaDoc("ABCDEFGHIJKLMNOP");
379         StringBuffer JavaDoc nameBuf = new StringBuffer JavaDoc(16);
380
381         int idx = 0;
382         char ch1, ch2;
383
384         while (idx < 32)
385         {
386
387             // Get the current encoded character pair from the encoded name string
388

389             ch1 = encnam.charAt(idx);
390             ch2 = encnam.charAt(idx + 1);
391
392             if (ch1 == 'C' && ch2 == 'A')
393             {
394
395                 // Append a <SPACE> character
396

397                 nameBuf.append(' ');
398             }
399             else
400             {
401
402                 // Convert back to a character code
403

404                 int val = convstr.indexOf(ch1) << 4;
405                 val += convstr.indexOf(ch2);
406
407                 // Append the current character to the decoded name
408

409                 nameBuf.append((char) (val & 0xFF));
410             }
411
412             // Update the encoded string index
413

414             idx += 2;
415
416         } // end while
417

418         // Return the decoded string
419

420         return nameBuf.toString();
421     }
422
423     /**
424      * Convert a host name string into RFC NetBIOS format.
425      *
426      * @param hostName Host name to be converted.
427      * @param nameType NetBIOS name type, added as the 16th byte of the name before conversion.
428      * @param buf Buffer to write the encoded name into.
429      * @param off Offset within the buffer to start writing.
430      * @return Buffer position
431      */

432     public static int EncodeName(String JavaDoc hostName, char nameType, byte[] buf, int off)
433     {
434
435         // Build the name string with the name type, make sure that the host
436
// name is uppercase.
437

438         StringBuffer JavaDoc hName = new StringBuffer JavaDoc(hostName.toUpperCase());
439
440         if (hName.length() > 15)
441             hName.setLength(15);
442
443         // Space pad the name then add the NetBIOS name type
444

445         while (hName.length() < 15)
446             hName.append(' ');
447         hName.append(nameType);
448
449         // Convert the NetBIOS name string to the RFC NetBIOS name format
450

451         String JavaDoc convstr = new String JavaDoc("ABCDEFGHIJKLMNOP");
452         int idx = 0;
453         int bufpos = off;
454
455         // Set the name length byte
456

457         buf[bufpos++] = 0x20;
458
459         // Copy the encoded NetBIOS name to the buffer
460

461         while (idx < hName.length())
462         {
463
464             // Get the current character from the host name string
465

466             char ch = hName.charAt(idx++);
467
468             if (ch == ' ')
469             {
470
471                 // Append an encoded <SPACE> character
472

473                 buf[bufpos++] = (byte) 'C';
474                 buf[bufpos++] = (byte) 'A';
475             }
476             else
477             {
478
479                 // Append octet for the current character
480

481                 buf[bufpos++] = (byte) convstr.charAt((int) ch / 16);
482                 buf[bufpos++] = (byte) convstr.charAt((int) ch % 16);
483             }
484
485         } // end while
486

487         // Null terminate the string
488

489         buf[bufpos++] = 0;
490         return bufpos;
491     }
492
493     /**
494      * Find a NetBIOS name on the network
495      *
496      * @param nbname NetBIOS name to search for, not yet RFC encoded
497      * @param nbType Name type, appended as the 16th byte of the name
498      * @param tmo Timeout value for receiving incoming datagrams
499      * @return NetBIOS name details
500      * @exception java.io.IOException If an I/O error occurs
501      */

502     public static NetBIOSName FindName(String JavaDoc nbName, char nbType, int tmo) throws java.io.IOException JavaDoc
503     {
504
505         // Call the main FindName method
506

507         return FindName(new NetBIOSName(nbName, nbType, false), tmo);
508     }
509
510     /**
511      * Find a NetBIOS name on the network
512      *
513      * @param nbname NetBIOS name to search for
514      * @param tmo Timeout value for receiving incoming datagrams
515      * @return NetBIOS name details
516      * @exception java.io.IOException If an I/O error occurs
517      */

518     public static NetBIOSName FindName(NetBIOSName nbName, int tmo) throws java.io.IOException JavaDoc
519     {
520
521         // Get the local address details
522

523         InetAddress JavaDoc locAddr = InetAddress.getLocalHost();
524
525         // Create a datagram socket
526

527         if (m_dgramSock == null)
528         {
529
530             // Create a datagram socket
531

532             m_dgramSock = new DatagramSocket JavaDoc();
533         }
534
535         // Set the datagram socket timeout, in milliseconds
536

537         m_dgramSock.setSoTimeout(tmo);
538
539         // Create a name lookup NetBIOS packet
540

541         NetBIOSPacket nbpkt = new NetBIOSPacket();
542         nbpkt.buildNameQueryRequest(nbName, m_tranIdx++);
543
544         // Get the local host numeric address
545

546         String JavaDoc locIP = locAddr.getHostAddress();
547         int dotIdx = locIP.indexOf('.');
548         if (dotIdx == -1)
549             return null;
550
551         // If a WINS server has been configured the request is sent directly to the WINS server, if
552
// not then a broadcast is done on the local subnet.
553

554         InetAddress JavaDoc destAddr = null;
555
556         if (hasWINSServer() == false)
557         {
558
559             // Check if the subnet mask has been set, if not then generate a subnet mask
560

561             if (getSubnetMask() == null)
562                 GenerateSubnetMask(null);
563
564             // Build a broadcast destination address
565

566             destAddr = InetAddress.getByName(getSubnetMask());
567         }
568         else
569         {
570
571             // Use the WINS server address
572

573             destAddr = getWINSServer();
574         }
575
576         // Build the name lookup request
577

578         DatagramPacket JavaDoc dgram = new DatagramPacket JavaDoc(nbpkt.getBuffer(), nbpkt.getLength(), destAddr,
579                 RFCNetBIOSProtocol.NAME_PORT);
580
581         // Allocate a receive datagram packet
582

583         byte[] rxbuf = new byte[FindNameBufferSize];
584         DatagramPacket JavaDoc rxdgram = new DatagramPacket JavaDoc(rxbuf, rxbuf.length);
585
586         // Create a NetBIOS packet using the receive buffer
587

588         NetBIOSPacket rxpkt = new NetBIOSPacket(rxbuf);
589
590         // DEBUG
591

592         if (m_debug)
593             nbpkt.DumpPacket(false);
594
595         // Send the find name datagram
596

597         m_dgramSock.send(dgram);
598
599         // Receive a reply datagram
600

601         boolean rxOK = false;
602
603         do
604         {
605
606             // Receive a datagram packet
607

608             m_dgramSock.receive(rxdgram);
609
610             // DEBUG
611

612             if (logger.isDebugEnabled() && m_debug)
613             {
614                 logger.debug("NetBIOS: Rx Datagram");
615                 rxpkt.DumpPacket(false);
616             }
617
618             // Check if this is a valid response datagram
619

620             if (rxpkt.isResponse() && rxpkt.getOpcode() == NetBIOSPacket.RESP_QUERY)
621                 rxOK = true;
622
623         } while (!rxOK);
624
625         // Get the list of names from the response, should only be one name
626

627         NetBIOSNameList nameList = rxpkt.getAnswerNameList();
628         if (nameList != null && nameList.numberOfNames() > 0)
629             return nameList.getName(0);
630         return null;
631     }
632
633     /**
634      * Build a list of nodes that own the specified NetBIOS name.
635      *
636      * @param nbname NetBIOS name to search for, not yet RFC encoded
637      * @param nbType Name type, appended as the 16th byte of the name
638      * @param tmo Timeout value for receiving incoming datagrams
639      * @return List of node name Strings
640      * @exception java.io.IOException If an I/O error occurs
641      */

642     public static StringList FindNameList(String JavaDoc nbName, char nbType, int tmo) throws IOException JavaDoc
643     {
644
645         // Get the local address details
646

647         InetAddress JavaDoc locAddr = InetAddress.getLocalHost();
648
649         // Create a datagram socket
650

651         if (m_dgramSock == null)
652         {
653
654             // Create a datagram socket
655

656             m_dgramSock = new DatagramSocket JavaDoc();
657         }
658
659         // Set the datagram socket timeout, in milliseconds
660

661         m_dgramSock.setSoTimeout(tmo);
662
663         // Create a name lookup NetBIOS packet
664

665         NetBIOSPacket nbpkt = new NetBIOSPacket();
666
667         nbpkt.setTransactionId(m_tranIdx++);
668         nbpkt.setOpcode(NetBIOSPacket.NAME_QUERY);
669         nbpkt.setFlags(NetBIOSPacket.FLG_BROADCAST);
670         nbpkt.setQuestionCount(1);
671         nbpkt.setQuestionName(nbName, nbType, NetBIOSPacket.NAME_TYPE_NB, NetBIOSPacket.NAME_CLASS_IN);
672
673         // Get the local host numeric address
674

675         String JavaDoc locIP = locAddr.getHostAddress();
676         int dotIdx = locIP.indexOf('.');
677         if (dotIdx == -1)
678             return null;
679
680         // If a WINS server has been configured the request is sent directly to the WINS server, if
681
// not then a broadcast is done on the local subnet.
682

683         InetAddress JavaDoc destAddr = null;
684
685         if (hasWINSServer() == false)
686         {
687
688             // Check if the subnet mask has been set, if not then generate a subnet mask
689

690             if (getSubnetMask() == null)
691                 GenerateSubnetMask(null);
692
693             // Build a broadcast destination address
694

695             destAddr = InetAddress.getByName(getSubnetMask());
696         }
697         else
698         {
699
700             // Use the WINS server address
701

702             destAddr = getWINSServer();
703         }
704
705         // Build the request datagram
706

707         DatagramPacket JavaDoc dgram = new DatagramPacket JavaDoc(nbpkt.getBuffer(), nbpkt.getLength(), destAddr,
708                 RFCNetBIOSProtocol.NAME_PORT);
709
710         // Allocate a receive datagram packet
711

712         byte[] rxbuf = new byte[FindNameBufferSize];
713         DatagramPacket JavaDoc rxdgram = new DatagramPacket JavaDoc(rxbuf, rxbuf.length);
714
715         // Create a NetBIOS packet using the receive buffer
716

717         NetBIOSPacket rxpkt = new NetBIOSPacket(rxbuf);
718
719         // DEBUG
720

721         if (m_debug)
722             nbpkt.DumpPacket(false);
723
724         // Create a vector to store the remote host addresses
725

726         Vector JavaDoc<InetAddress JavaDoc> addrList = new Vector JavaDoc<InetAddress JavaDoc>();
727
728         // Calculate the end time, to stop receiving datagrams
729

730         long endTime = System.currentTimeMillis() + tmo;
731
732         // Send the find name datagram
733

734         m_dgramSock.send(dgram);
735
736         // Receive reply datagrams
737

738         do
739         {
740
741             // Receive a datagram packet
742

743             try
744             {
745                 m_dgramSock.receive(rxdgram);
746
747                 // DEBUG
748

749                 if (logger.isDebugEnabled() && m_debug)
750                 {
751                     logger.debug("NetBIOS: Rx Datagram");
752                     rxpkt.DumpPacket(false);
753                 }
754
755                 // Check if this is a valid response datagram
756

757                 if (rxpkt.isResponse() && rxpkt.getOpcode() == NetBIOSPacket.RESP_QUERY)
758                 {
759
760                     // Get the address of the remote host for this datagram and add it to the list
761
// of responders
762

763                     addrList.add(rxdgram.getAddress());
764                 }
765             }
766             catch (java.io.IOException JavaDoc ex)
767             {
768
769                 // DEBUG
770

771                 if (logger.isDebugEnabled() && m_debug)
772                     logger.debug(ex.toString());
773             }
774
775         } while (System.currentTimeMillis() < endTime);
776
777         // Check if we received any replies
778

779         if (addrList.size() == 0)
780             return null;
781
782         // Create a node name list
783

784         StringList nameList = new StringList();
785
786         // Convert the reply addresses to node names
787

788         for (int i = 0; i < addrList.size(); i++)
789         {
790
791             // Get the current address from the list
792

793             InetAddress JavaDoc addr = addrList.elementAt(i);
794
795             // Convert the address to a node name string
796

797             String JavaDoc name = NetBIOSName(addr.getHostName());
798
799             // Check if the name is already in the name list
800

801             if (!nameList.containsString(name))
802                 nameList.addString(name);
803         }
804
805         // Return the node name list
806

807         return nameList;
808     }
809
810     /**
811      * Get the NetBIOS name list for the specified IP address
812      *
813      * @param ipAddr String
814      * @return NetBIOSNameList
815      */

816     public static NetBIOSNameList FindNamesForAddress(String JavaDoc ipAddr) throws UnknownHostException JavaDoc, SocketException JavaDoc
817     {
818
819         // Create a datagram socket
820

821         if (m_dgramSock == null)
822         {
823
824             // Create a datagram socket
825

826             m_dgramSock = new DatagramSocket JavaDoc();
827         }
828
829         // Set the datagram socket timeout, in milliseconds
830

831         m_dgramSock.setSoTimeout(2000);
832
833         // Create a name lookup NetBIOS packet
834

835         NetBIOSPacket nbpkt = new NetBIOSPacket();
836
837         nbpkt.setTransactionId(m_tranIdx++);
838         nbpkt.setOpcode(NetBIOSPacket.NAME_QUERY);
839         nbpkt.setFlags(NetBIOSPacket.FLG_BROADCAST);
840         nbpkt.setQuestionCount(1);
841         nbpkt.setQuestionName("*\0\0\0\0\0\0\0\0\0\0\0\0\0\0", NetBIOSName.WorkStation, NetBIOSPacket.NAME_TYPE_NBSTAT,
842                 NetBIOSPacket.NAME_CLASS_IN);
843
844         // Send the request to the specified address
845

846         InetAddress JavaDoc destAddr = InetAddress.getByName(ipAddr);
847         DatagramPacket JavaDoc dgram = new DatagramPacket JavaDoc(nbpkt.getBuffer(), nbpkt.getLength(), destAddr,
848                 RFCNetBIOSProtocol.NAME_PORT);
849
850         // Allocate a receive datagram packet
851

852         byte[] rxbuf = new byte[FindNameBufferSize];
853         DatagramPacket JavaDoc rxdgram = new DatagramPacket JavaDoc(rxbuf, rxbuf.length);
854
855         // Create a NetBIOS packet using the receive buffer
856

857         NetBIOSPacket rxpkt = new NetBIOSPacket(rxbuf);
858
859         // DEBUG
860

861         if (logger.isDebugEnabled() && m_debug)
862             nbpkt.DumpPacket(false);
863
864         // Create a vector to store the remote hosts NetBIOS names
865

866         NetBIOSNameList nameList = null;
867
868         try
869         {
870
871             // Send the name query datagram
872

873             m_dgramSock.send(dgram);
874
875             // Receive a datagram packet
876

877             m_dgramSock.receive(rxdgram);
878
879             // DEBUG
880

881             if (logger.isDebugEnabled() && m_debug)
882             {
883                 logger.debug("NetBIOS: Rx Datagram");
884                 rxpkt.DumpPacket(false);
885             }
886
887             // Check if this is a valid response datagram
888

889             if (rxpkt.isResponse() && rxpkt.getOpcode() == NetBIOSPacket.RESP_QUERY && rxpkt.getAnswerCount() >= 1)
890             {
891
892                 // Get the received name list
893

894                 nameList = rxpkt.getAdapterStatusNameList();
895                 
896                 // If the name list is valid update the names with the original address that was connected to
897

898                 if( nameList != null)
899                 {
900                     for ( int i = 0; i < nameList.numberOfNames(); i++)
901                     {
902                         NetBIOSName nbName = nameList.getName(i);
903                         nbName.addIPAddress(destAddr.getAddress());
904                     }
905                 }
906             }
907         }
908         catch (java.io.IOException JavaDoc ex)
909         {
910
911             // DEBUG
912

913             if (logger.isDebugEnabled() && m_debug)
914                 logger.debug(ex.toString());
915
916             // Unknown host
917

918             throw new UnknownHostException JavaDoc(ipAddr);
919         }
920
921         // Return the NetBIOS name list
922

923         return nameList;
924     }
925
926     /**
927      * Determine the subnet mask from the local hosts TCP/IP address
928      *
929      * @param addr TCP/IP address to set the subnet mask for, in 'nnn.nnn.nnn.nnn' format.
930      */

931     public static String JavaDoc GenerateSubnetMask(String JavaDoc addr) throws java.net.UnknownHostException JavaDoc
932     {
933
934         // Set the TCP/IP address string
935

936         String JavaDoc localIP = addr;
937
938         // Get the local TCP/IP address, if a null string has been specified
939

940         if (localIP == null)
941             localIP = InetAddress.getLocalHost().getHostAddress();
942
943         // Find the location of the first dot in the TCP/IP address
944

945         int dotPos = localIP.indexOf('.');
946         if (dotPos != -1)
947         {
948
949             // Extract the leading IP address value
950

951             String JavaDoc ipStr = localIP.substring(0, dotPos);
952             int ipVal = Integer.valueOf(ipStr).intValue();
953
954             // Determine the subnet mask to use
955

956             if (ipVal <= 127)
957             {
958
959                 // Class A address
960

961                 m_subnetMask = "" + ipVal + ".255.255.255";
962             }
963             else if (ipVal <= 191)
964             {
965
966                 // Class B adddress
967

968                 dotPos++;
969                 while (localIP.charAt(dotPos) != '.' && dotPos < localIP.length())
970                     dotPos++;
971
972                 if (dotPos < localIP.length())
973                     m_subnetMask = localIP.substring(0, dotPos) + ".255.255";
974             }
975             else if (ipVal <= 223)
976             {
977
978                 // Class C address
979

980                 dotPos++;
981                 int dotCnt = 1;
982
983                 while (dotCnt < 3 && dotPos < localIP.length())
984                 {
985
986                     // Check if the current character is a dot
987

988                     if (localIP.charAt(dotPos++) == '.')
989                         dotCnt++;
990                 }
991
992                 if (dotPos < localIP.length())
993                     m_subnetMask = localIP.substring(0, dotPos - 1) + ".255";
994             }
995         }
996
997         // Check if the subnet mask has been set, if not then use a general
998
// broadcast mask
999

1000        if (m_subnetMask == null)
1001        {
1002
1003            // Invalid TCP/IP address string format, use a general broadcast mask
1004
// for now.
1005

1006            m_subnetMask = "255.255.255.255";
1007        }
1008
1009        // DEBUG
1010

1011        if (logger.isDebugEnabled() && m_debug)
1012            logger.debug("NetBIOS: Set subnet mask to " + m_subnetMask);
1013
1014        // Return the subnet mask string
1015

1016        return m_subnetMask;
1017    }
1018
1019    /**
1020     * Get the WINS/NetBIOS name lookup timeout, in milliseconds.
1021     *
1022     * @return int
1023     */

1024    public static int getLookupTimeout()
1025    {
1026        return m_lookupTmo;
1027    }
1028
1029    /**
1030     * Return the name lookup type that is used when setting up new sessions, valid values are
1031     * DNSOnly, WINSOnly, WINSAndDNS. DNSOnly is the default type.
1032     *
1033     * @return int
1034     */

1035    public static int getLookupType()
1036    {
1037        return m_lookupType;
1038    }
1039
1040    /**
1041     * Return the subnet mask string
1042     *
1043     * @return Subnet mask string, in 'nnn.nnn.nnn.nnn' format
1044     */

1045    public static String JavaDoc getSubnetMask()
1046    {
1047        return m_subnetMask;
1048    }
1049
1050    /**
1051     * Determine if the WINS server address is configured
1052     *
1053     * @return boolean
1054     */

1055    public final static boolean hasWINSServer()
1056    {
1057        return m_winsServer != null ? true : false;
1058    }
1059
1060    /**
1061     * Return the WINS server address
1062     *
1063     * @return InetAddress
1064     */

1065    public final static InetAddress JavaDoc getWINSServer()
1066    {
1067        return m_winsServer;
1068    }
1069
1070    /**
1071     * Determine if SMB session debugging is enabled
1072     *
1073     * @return true if debugging is enabled, else false.
1074     */

1075    public static boolean isDebug()
1076    {
1077        return m_debug;
1078    }
1079
1080    /**
1081     * Return the next session index
1082     *
1083     * @return int
1084     */

1085    private final static synchronized int getSessionId()
1086    {
1087        return m_sessIdx++;
1088    }
1089
1090    /**
1091     * Return the JVM unique id, used when generating caller names
1092     *
1093     * @return int
1094     */

1095    public final static int getJVMIndex()
1096    {
1097        return m_jvmIdx;
1098    }
1099
1100    /**
1101     * Convert the TCP/IP host name to a NetBIOS name string.
1102     *
1103     * @return java.lang.String
1104     * @param hostName java.lang.String
1105     */

1106    public static String JavaDoc NetBIOSName(String JavaDoc hostName)
1107    {
1108
1109        // Check if the host name contains a domain name
1110

1111        String JavaDoc nbName = new String JavaDoc(hostName.toUpperCase());
1112        int pos = nbName.indexOf(".");
1113
1114        if (pos != -1)
1115        {
1116
1117            // Strip the domain name for the NetBIOS name
1118

1119            nbName = nbName.substring(0, pos);
1120        }
1121
1122        // Return the NetBIOS name string
1123

1124        return nbName;
1125    }
1126
1127    /**
1128     * Enable/disable NetBIOS session debugging
1129     *
1130     * @param dbg true to enable debugging, else false
1131     */

1132    public static void setDebug(boolean dbg)
1133    {
1134        m_debug = dbg;
1135    }
1136
1137    /**
1138     * Set the WINS/NetBIOS name lookup timeout value, in milliseconds.
1139     *
1140     * @param tmo int
1141     */

1142    public static void setLookupTimeout(int tmo)
1143    {
1144        if (tmo >= 250)
1145            m_lookupTmo = tmo;
1146    }
1147
1148    /**
1149     * Set the name lookup type(s) to be used when opening new sessions, valid values are DNSOnly,
1150     * WINSOnly, WINSAndDNS. DNSOnly is the default type.
1151     *
1152     * @param typ int
1153     */

1154    public static void setLookupType(int typ)
1155    {
1156        if (typ >= DNSOnly && typ <= WINSAndDNS)
1157            m_lookupType = typ;
1158    }
1159
1160    /**
1161     * Set the subnet mask string
1162     *
1163     * @param subnet Subnet mask string, in 'nnn.nnn.nnn.nnn' format
1164     */

1165    public static void setSubnetMask(String JavaDoc subnet)
1166    {
1167        m_subnetMask = subnet;
1168    }
1169
1170    /**
1171     * Set the WINS server address
1172     *
1173     * @param addr InetAddress
1174     */

1175    public final static void setWINSServer(InetAddress JavaDoc addr)
1176    {
1177        m_winsServer = addr;
1178    }
1179
1180    /**
1181     * Get the NetBIOS adapter status for the specified node.
1182     *
1183     * @return java.util.Vector
1184     * @param nodeName java.lang.String
1185     */

1186    private static Vector JavaDoc AdapterStatus(String JavaDoc nodeName) throws java.io.IOException JavaDoc
1187    {
1188
1189        // Create the socket
1190

1191        DatagramSocket JavaDoc nameSock = new DatagramSocket JavaDoc();
1192
1193        // Enable the timeout on the socket
1194

1195        nameSock.setSoTimeout(2000);
1196
1197        // Create an adapter status NetBIOS packet
1198

1199        NetBIOSPacket nbpkt = new NetBIOSPacket();
1200
1201        // nbpkt.setTransactionId( m_tranIdx++);
1202
nbpkt.setTransactionId(9999);
1203        nbpkt.setOpcode(NetBIOSPacket.NAME_QUERY);
1204        nbpkt.setFlags(NetBIOSPacket.FLG_BROADCAST);
1205        nbpkt.setQuestionCount(1);
1206        nbpkt.setQuestionName(nodeName, NetBIOSName.WorkStation, NetBIOSPacket.NAME_TYPE_NBSTAT,
1207                NetBIOSPacket.NAME_CLASS_IN);
1208
1209        // Build a broadcast destination address
1210

1211        InetAddress JavaDoc destAddr = InetAddress.getByName(nodeName);
1212        DatagramPacket JavaDoc dgram = new DatagramPacket JavaDoc(nbpkt.getBuffer(), nbpkt.getLength(), destAddr,
1213                RFCNetBIOSProtocol.NAME_PORT);
1214
1215        // Allocate a receive datagram packet
1216

1217        byte[] rxbuf = new byte[512];
1218        DatagramPacket JavaDoc rxdgram = new DatagramPacket JavaDoc(rxbuf, rxbuf.length);
1219
1220        // Create a NetBIOS packet using the receive buffer
1221

1222        NetBIOSPacket rxpkt = new NetBIOSPacket(rxbuf);
1223
1224        // DEBUG
1225

1226        if (logger.isDebugEnabled() && m_debug)
1227            nbpkt.DumpPacket(false);
1228
1229        // Send the find name datagram
1230

1231        nameSock.send(dgram);
1232
1233        // Receive a reply datagram
1234

1235        boolean rxOK = false;
1236
1237        do
1238        {
1239
1240            // Receive a datagram packet
1241

1242            nameSock.receive(rxdgram);
1243
1244            // DEBUG
1245

1246            if (logger.isDebugEnabled() && m_debug)
1247            {
1248                logger.debug("NetBIOS: Rx Datagram");
1249                rxpkt.DumpPacket(false);
1250            }
1251
1252            // Check if this is a valid response datagram
1253

1254            if (rxpkt.isResponse() && rxpkt.getOpcode() == NetBIOSPacket.RESP_QUERY)
1255                rxOK = true;
1256
1257        } while (!rxOK);
1258
1259        // Return the remote host address
1260

1261        return null;
1262    }
1263
1264    /**
1265     * Connect to a remote host.
1266     *
1267     * @param remHost Remote host node name/NetBIOS name.
1268     * @param locName Local name/NetBIOS name.
1269     * @param remAddr Optional remote address, if null then lookup will be done to convert name to
1270     * address
1271     * @exception java.io.IOException I/O error occurred.
1272     * @exception java.net.UnknownHostException Remote host is unknown.
1273     */

1274    public void Open(String JavaDoc remHost, String JavaDoc locName, String JavaDoc remAddr) throws java.io.IOException JavaDoc,
1275            java.net.UnknownHostException JavaDoc
1276    {
1277
1278        // Debug mode
1279

1280        if (logger.isDebugEnabled() && m_debug)
1281            logger.debug("NetBIOS: Call " + remHost);
1282
1283        // Convert the remote host name to an address
1284

1285        boolean dnsLookup = false;
1286        InetAddress JavaDoc addr = null;
1287
1288        // Set the remote address is specified
1289

1290        if (remAddr != null)
1291        {
1292
1293            // Use the specified remote address
1294

1295            addr = InetAddress.getByName(remAddr);
1296        }
1297        else
1298        {
1299
1300            // Try a WINS/NetBIOS type name lookup, if enabled
1301

1302            if (getLookupType() != DNSOnly)
1303            {
1304                try
1305                {
1306                    NetBIOSName netName = FindName(remHost, NetBIOSName.FileServer, 500);
1307                    if (netName != null && netName.numberOfAddresses() > 0)
1308                        addr = InetAddress.getByName(netName.getIPAddressString(0));
1309                }
1310                catch (Exception JavaDoc ex)
1311                {
1312                }
1313            }
1314
1315            // Try a DNS type name lookup, if enabled
1316

1317            if (addr == null && getLookupType() != WINSOnly)
1318            {
1319                addr = InetAddress.getByName(remHost);
1320                dnsLookup = true;
1321            }
1322        }
1323
1324        // Check if we translated the remote host name to an address
1325

1326        if (addr == null)
1327            throw new java.net.UnknownHostException JavaDoc(remHost);
1328
1329        // Debug mode
1330

1331        if (logger.isDebugEnabled() && m_debug)
1332            logger.debug("NetBIOS: Remote node hase address " + addr.getHostAddress() + " ("
1333                    + (dnsLookup ? "DNS" : "WINS") + ")");
1334
1335        // Determine the remote name to call
1336

1337        String JavaDoc remoteName = null;
1338
1339        if (getRemoteNameType() == NetBIOSName.FileServer && useWildcardFileServerName() == true)
1340            remoteName = "*SMBSERVER";
1341        else
1342            remoteName = remHost;
1343
1344        // Open a session to the remote server
1345

1346        int resp = openSession(remoteName, addr);
1347
1348        // Check the server response
1349

1350        if (resp == RFCNetBIOSProtocol.SESSION_ACK)
1351            return;
1352        else if (resp == RFCNetBIOSProtocol.SESSION_REJECT)
1353        {
1354
1355            // Try the connection again with the remote host name
1356

1357            if (remoteName.equals(remHost) == false)
1358                resp = openSession(remHost, addr);
1359
1360            // Check if we got a valid response this time
1361

1362            if (resp == RFCNetBIOSProtocol.SESSION_ACK)
1363                return;
1364
1365            // Server rejected the connection
1366

1367            throw new java.io.IOException JavaDoc("NetBIOS session reject");
1368        }
1369        else if (resp == RFCNetBIOSProtocol.SESSION_RETARGET)
1370            throw new java.io.IOException JavaDoc("NetBIOS ReTarget");
1371
1372        // Invalid session response, hangup the session
1373

1374        Close();
1375        throw new java.io.IOException JavaDoc("Invalid NetBIOS response, 0x" + Integer.toHexString(resp));
1376    }
1377
1378    /**
1379     * Open a NetBIOS session to a remote server
1380     *
1381     * @param remoteName String
1382     * @param addr InetAddress
1383     * @return int
1384     * @exception IOException
1385     */

1386    private final int openSession(String JavaDoc remoteName, InetAddress JavaDoc addr) throws IOException JavaDoc
1387    {
1388
1389        // Create the socket
1390

1391        m_nbSocket = new Socket JavaDoc(addr, m_remotePort);
1392
1393        // Enable the timeout on the socket, and disable Nagle algorithm
1394

1395        m_nbSocket.setSoTimeout(m_tmo);
1396        m_nbSocket.setTcpNoDelay(true);
1397
1398        // Attach input/output streams to the socket
1399

1400        m_nbIn = new DataInputStream JavaDoc(m_nbSocket.getInputStream());
1401        m_nbOut = new DataOutputStream JavaDoc(m_nbSocket.getOutputStream());
1402
1403        // Allocate a buffer to receive the session response
1404

1405        byte[] inpkt = new byte[RFCNetBIOSProtocol.SESSRESP_LEN];
1406
1407        // Create the from/to NetBIOS names
1408

1409        NetBIOSName fromName = createUniqueCallerName();
1410        NetBIOSName toName = new NetBIOSName(remoteName, getRemoteNameType(), false);
1411
1412        // Debug
1413

1414        if (logger.isDebugEnabled() && m_debug)
1415            logger.debug("NetBIOS: Call from " + fromName + " to " + toName);
1416
1417        // Build the session request packet
1418

1419        NetBIOSPacket nbPkt = new NetBIOSPacket();
1420        nbPkt.buildSessionSetupRequest(fromName, toName);
1421
1422        // Send the session request packet
1423

1424        m_nbOut.write(nbPkt.getBuffer(), 0, nbPkt.getLength());
1425
1426        // Allocate a buffer for the session request response, and read the response
1427

1428        int resp = -1;
1429
1430        if (m_nbIn.read(inpkt, 0, RFCNetBIOSProtocol.SESSRESP_LEN) >= RFCNetBIOSProtocol.HEADER_LEN)
1431        {
1432
1433            // Check the session request response
1434

1435            resp = (int) (inpkt[0] & 0xFF);
1436
1437            // Debug mode
1438

1439            if (logger.isDebugEnabled() && m_debug)
1440                logger.debug("NetBIOS: Rx " + NetBIOSPacket.getTypeAsString(resp));
1441        }
1442
1443        // Check for a positive response
1444

1445        if (resp != RFCNetBIOSProtocol.SESSION_ACK)
1446        {
1447
1448            // Close the socket and streams
1449

1450            m_nbIn.close();
1451            m_nbIn = null;
1452
1453            m_nbOut.close();
1454            m_nbOut = null;
1455
1456            m_nbSocket.close();
1457            m_nbSocket = null;
1458        }
1459
1460        // Return the response code
1461

1462        return resp;
1463    }
1464
1465    /**
1466     * Return the local NetBIOS name type.
1467     *
1468     * @return char
1469     */

1470    public char getLocalNameType()
1471    {
1472        return m_locNameType;
1473    }
1474
1475    /**
1476     * Return the remote NetBIOS name type.
1477     *
1478     * @return char
1479     */

1480    public char getRemoteNameType()
1481    {
1482        return m_remNameType;
1483    }
1484
1485    /**
1486     * Get the session timeout value
1487     *
1488     * @return NetBIOS session timeout value
1489     */

1490    public int getTimeout()
1491    {
1492        return m_tmo;
1493    }
1494
1495    /**
1496     * Close the NetBIOS session.
1497     *
1498     * @exception IOException If an I/O error occurs
1499     */

1500    public void Close() throws IOException JavaDoc
1501    {
1502
1503        // Debug mode
1504

1505        if (logger.isDebugEnabled() && m_debug)
1506            logger.debug("NetBIOS: HangUp");
1507
1508        // Close the session if active
1509

1510        if (m_nbSocket != null)
1511        {
1512            m_nbSocket.close();
1513            m_nbSocket = null;
1514        }
1515    }
1516
1517    /**
1518     * Receive a data packet from the remote host.
1519     *
1520     * @param buf Byte buffer to receive the data into.
1521     * @param tmo Receive timeout in milliseconds, or zero for no timeout
1522     * @return Length of the received data.
1523     * @exception java.io.IOException I/O error occurred.
1524     */

1525    public int Receive(byte[] buf, int tmo) throws java.io.IOException JavaDoc
1526    {
1527
1528        // Set the read timeout
1529

1530        if (tmo != m_tmo)
1531        {
1532            m_nbSocket.setSoTimeout(tmo);
1533            m_tmo = tmo;
1534        }
1535
1536        // Read a data packet, dump any session keep alive packets
1537

1538        int pkttyp;
1539        int rdlen;
1540
1541        do
1542        {
1543
1544            // Read a packet header
1545

1546            rdlen = m_nbIn.read(buf, 0, RFCNetBIOSProtocol.HEADER_LEN);
1547
1548            // Debug mode
1549

1550            if (logger.isDebugEnabled() && m_debug)
1551                logger.debug("NetBIOS: Read " + rdlen + " bytes");
1552
1553            // Check if a header was received
1554

1555            if (rdlen < RFCNetBIOSProtocol.HEADER_LEN)
1556                throw new java.io.IOException JavaDoc("NetBIOS Short Read");
1557
1558            // Get the packet type from the header
1559

1560            pkttyp = (int) (buf[0] & 0xFF);
1561
1562        } while (pkttyp == RFCNetBIOSProtocol.SESSION_KEEPALIVE);
1563
1564        // Debug mode
1565

1566        if (logger.isDebugEnabled() && m_debug)
1567            logger.debug("NetBIOS: Rx Pkt Type = " + pkttyp + ", " + Integer.toHexString(pkttyp));
1568
1569        // Check that the packet is a session data packet
1570

1571        if (pkttyp != RFCNetBIOSProtocol.SESSION_MESSAGE)
1572            throw new java.io.IOException JavaDoc("NetBIOS Unknown Packet Type, " + pkttyp);
1573
1574        // Extract the data size from the packet header
1575

1576        int pktlen = (int) DataPacker.getShort(buf, 2);
1577        if (logger.isDebugEnabled() && m_debug)
1578            logger.debug("NetBIOS: Rx Data Len = " + pktlen);
1579
1580        // Check if the user buffer is long enough to contain the data
1581

1582        if (buf.length < (pktlen + RFCNetBIOSProtocol.HEADER_LEN))
1583        {
1584
1585            // Debug mode
1586

1587            logger.debug("NetBIOS: Rx Pkt Type = " + pkttyp + ", " + Integer.toHexString(pkttyp));
1588            logger.debug("NetBIOS: Rx Buf Too Small pkt=" + pktlen + " buflen=" + buf.length);
1589            HexDump.Dump(buf, 16, 0);
1590
1591            throw new java.io.IOException JavaDoc("NetBIOS Recv Buffer Too Small (pkt=" + pktlen + "/buf=" + buf.length + ")");
1592        }
1593
1594        // Read the data part of the packet into the users buffer, this may take
1595
// several reads
1596

1597        int totlen = 0;
1598        int offset = RFCNetBIOSProtocol.HEADER_LEN;
1599
1600        while (pktlen > 0)
1601        {
1602
1603            // Read the data
1604

1605            rdlen = m_nbIn.read(buf, offset, pktlen);
1606
1607            // Update the received length and remaining data length
1608

1609            totlen += rdlen;
1610            pktlen -= rdlen;
1611
1612            // Update the user buffer offset as more reads will be required
1613
// to complete the data read
1614

1615            offset += rdlen;
1616
1617        } // end while reading data
1618

1619        // Return the received data length, not including the NetBIOS header
1620

1621        return totlen;
1622    }
1623
1624    /**
1625     * Send a data packet to the remote host.
1626     *
1627     * @param data Byte array containing the data to be sent.
1628     * @param siz Length of the data to send.
1629     * @return true if the data was sent successfully, else false.
1630     * @exception java.io.IOException I/O error occurred.
1631     */

1632    public boolean Send(byte[] data, int siz) throws java.io.IOException JavaDoc
1633    {
1634
1635        // Check that the session is valid
1636

1637        if (m_nbSocket == null)
1638            return false;
1639
1640        // Debug mode
1641

1642        if (logger.isDebugEnabled() && m_debug)
1643            logger.debug("NetBIOS: Tx " + siz + " bytes");
1644
1645        // Fill in the NetBIOS message header, this is already allocated as
1646
// part of the users buffer.
1647

1648        data[0] = (byte) RFCNetBIOSProtocol.SESSION_MESSAGE;
1649        data[1] = (byte) 0;
1650
1651        DataPacker.putShort((short) siz, data, 2);
1652
1653        // Output the data packet
1654

1655        int bufSiz = siz + RFCNetBIOSProtocol.HEADER_LEN;
1656        m_nbOut.write(data, 0, bufSiz);
1657        return true;
1658    }
1659
1660    /**
1661     * Set the local NetBIOS name type for this session.
1662     *
1663     * @param nameType int
1664     */

1665    public void setLocalNameType(char nameType)
1666    {
1667        m_locNameType = nameType;
1668    }
1669
1670    /**
1671     * Set the remote NetBIOS name type.
1672     *
1673     * @param param char
1674     */

1675    public void setRemoteNameType(char nameType)
1676    {
1677        m_remNameType = nameType;
1678    }
1679
1680    /**
1681     * Set the session timeout value
1682     *
1683     * @param tmo Session timeout value
1684     */

1685    public void setTimeout(int tmo)
1686    {
1687        m_tmo = tmo;
1688    }
1689
1690    /**
1691     * Set the caller session name template string that is appended to the local host name to create
1692     * a unique caller name.
1693     *
1694     * @param template String
1695     * @exception NameTemplateExcepition
1696     */

1697    public final static void setCallerNameTemplate(String JavaDoc template) throws NameTemplateException
1698    {
1699
1700        // Check if the template string is valid, is not too long
1701

1702        if (template == null || template.length() == 0 || template.length() > MaxCallerNameTemplateLength)
1703            throw new NameTemplateException("Invalid template string, " + template);
1704
1705        // Template must contain at least one session id template character
1706

1707        if (template.indexOf(SessionIdChar) == -1)
1708            throw new NameTemplateException("No session id character in template");
1709
1710        // Check if the template contains any invalid characters
1711

1712        for (int i = 0; i < template.length(); i++)
1713        {
1714            if (ValidTemplateChars.indexOf(template.charAt(i)) == -1)
1715                throw new NameTemplateException("Invalid character in template, '" + template.charAt(i) + "'");
1716        }
1717
1718        // Set the caller name template string
1719

1720        m_callerTemplate = template;
1721
1722        // Clear the local name part string so that it will be regenerated to match the new template
1723
// string
1724

1725        m_localNamePart = null;
1726    }
1727
1728    /**
1729     * Set the JVM index, used to generate unique caller names when multiple JVMs are run on the
1730     * same host.
1731     *
1732     * @param jvmIdx int
1733     */

1734    public final static void setJVMIndex(int jvmIdx)
1735    {
1736        if (jvmIdx >= 0)
1737            m_jvmIdx = jvmIdx;
1738    }
1739
1740    /**
1741     * Create a unique caller name for a new NetBIOS session. The unique name contains the local
1742     * host name plus an index that is unique for this JVM, plus an optional JVM index.
1743     *
1744     * @return NetBIOSName
1745     */

1746    private final NetBIOSName createUniqueCallerName()
1747    {
1748
1749        // Check if the local name part has been set
1750

1751        if (m_localNamePart == null)
1752        {
1753
1754            String JavaDoc localName = null;
1755
1756            try
1757            {
1758                localName = InetAddress.getLocalHost().getHostName();
1759            }
1760            catch (Exception JavaDoc ex)
1761            {
1762            }
1763
1764            // Check if the name contains a domain
1765

1766            int pos = localName.indexOf(".");
1767
1768            if (pos != -1)
1769                localName = localName.substring(0, pos);
1770
1771            // Truncate the name if the host name plus the template is longer than 15 characters.
1772

1773            int nameLen = 16 - m_callerTemplate.length();
1774
1775            if (localName.length() > nameLen)
1776                localName = localName.substring(0, nameLen - 1);
1777
1778            // Set the local host name part
1779

1780            m_localNamePart = localName.toUpperCase();
1781        }
1782
1783        // Get a unique session id and the unique JVM id
1784

1785        int sessId = getSessionId();
1786        int jvmId = getJVMIndex();
1787
1788        // Build the NetBIOS name string
1789

1790        StringBuffer JavaDoc nameBuf = new StringBuffer JavaDoc(16);
1791
1792        nameBuf.append(m_localNamePart);
1793
1794        // Process the caller name template string
1795

1796        int idx = 0;
1797        int len = -1;
1798
1799        while (idx < m_callerTemplate.length())
1800        {
1801
1802            // Get the current template character
1803

1804            char ch = m_callerTemplate.charAt(idx++);
1805
1806            switch (ch)
1807            {
1808
1809            // Session id
1810

1811            case SessionIdChar:
1812                len = findRepeatLength(m_callerTemplate, idx, SessionIdChar);
1813                appendZeroPaddedHexValue(sessId, len, nameBuf);
1814                idx += len - 1;
1815                break;
1816
1817            // JVM id
1818

1819            case JVMIdChar:
1820                len = findRepeatLength(m_callerTemplate, idx, JVMIdChar);
1821                appendZeroPaddedHexValue(jvmId, len, nameBuf);
1822                idx += len - 1;
1823                break;
1824
1825            // Pass any other characters through to the name string
1826

1827            default:
1828                nameBuf.append(ch);
1829                break;
1830            }
1831        }
1832
1833        // Create the NetBIOS name object
1834

1835        return new NetBIOSName(nameBuf.toString(), getLocalNameType(), false);
1836    }
1837
1838    /**
1839     * Find the length of the character block in the specified string
1840     *
1841     * @param str String
1842     * @param pos int
1843     * @param ch char
1844     * @return int
1845     */

1846    private final int findRepeatLength(String JavaDoc str, int pos, char ch)
1847    {
1848        int len = 1;
1849
1850        while (pos < str.length() && str.charAt(pos++) == ch)
1851            len++;
1852        return len;
1853    }
1854
1855    /**
1856     * Append a zero filled hex string to the specified string
1857     *
1858     * @param val int
1859     * @param len int
1860     * @param str StringBuffer
1861     */

1862    private final void appendZeroPaddedHexValue(int val, int len, StringBuffer JavaDoc str)
1863    {
1864
1865        // Create the hex string of the value
1866

1867        String JavaDoc hex = Integer.toHexString(val);
1868
1869        // Pad the final string as required
1870

1871        for (int i = 0; i < len - hex.length(); i++)
1872            str.append("0");
1873        str.append(hex);
1874    }
1875
1876    /**
1877     * Return the default socket timeout value
1878     *
1879     * @return int
1880     */

1881    public static final int getDefaultTimeout()
1882    {
1883        return _defTimeout;
1884    }
1885
1886    /**
1887     * Set the default socket timeout for new sessions
1888     *
1889     * @param tmo int
1890     */

1891    public static final void setDefaultTimeout(int tmo)
1892    {
1893        _defTimeout = tmo;
1894    }
1895
1896    /**
1897     * Return the use wildcard file server name flag status. If true the target name when conencting
1898     * to a remote file server will be '*SMBSERVER', if false the remote name will be used.
1899     *
1900     * @return boolean
1901     */

1902    public static final boolean useWildcardFileServerName()
1903    {
1904        return m_useWildcardFileServer;
1905    }
1906
1907    /**
1908     * Set the use wildcard file server name flag. If true the target name when conencting to a
1909     * remote file server will be '*SMBSERVER', if false the remote name will be used.
1910     *
1911     * @param useWildcard boolean
1912     */

1913    public static final void setWildcardFileServerName(boolean useWildcard)
1914    {
1915        m_useWildcardFileServer = useWildcard;
1916    }
1917
1918    /**
1919     * Finalize the NetBIOS session object
1920     */

1921    protected void finalize()
1922    {
1923
1924        // Close the socket
1925

1926        if (m_nbSocket != null)
1927        {
1928            try
1929            {
1930                m_nbSocket.close();
1931            }
1932            catch (java.io.IOException JavaDoc ex)
1933            {
1934            }
1935            m_nbSocket = null;
1936        }
1937    }
1938}
Popular Tags