KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > smb > server > SMBSrvSession


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.smb.server;
18
19 import java.io.IOException JavaDoc;
20 import java.net.InetAddress JavaDoc;
21 import java.net.SocketException JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.Hashtable JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 import org.alfresco.filesys.netbios.NetBIOSException;
27 import org.alfresco.filesys.netbios.NetBIOSName;
28 import org.alfresco.filesys.netbios.NetBIOSPacket;
29 import org.alfresco.filesys.netbios.NetBIOSSession;
30 import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
31 import org.alfresco.filesys.server.SrvSession;
32 import org.alfresco.filesys.server.auth.SrvAuthenticator;
33 import org.alfresco.filesys.server.core.DeviceInterface;
34 import org.alfresco.filesys.server.core.SharedDevice;
35 import org.alfresco.filesys.server.filesys.DiskDeviceContext;
36 import org.alfresco.filesys.server.filesys.DiskInterface;
37 import org.alfresco.filesys.server.filesys.NetworkFile;
38 import org.alfresco.filesys.server.filesys.SearchContext;
39 import org.alfresco.filesys.server.filesys.TooManyConnectionsException;
40 import org.alfresco.filesys.server.filesys.TreeConnection;
41 import org.alfresco.filesys.smb.Capability;
42 import org.alfresco.filesys.smb.DataType;
43 import org.alfresco.filesys.smb.Dialect;
44 import org.alfresco.filesys.smb.DialectSelector;
45 import org.alfresco.filesys.smb.NTTime;
46 import org.alfresco.filesys.smb.PacketType;
47 import org.alfresco.filesys.smb.SMBDate;
48 import org.alfresco.filesys.smb.SMBErrorText;
49 import org.alfresco.filesys.smb.SMBStatus;
50 import org.alfresco.filesys.smb.server.notify.NotifyRequest;
51 import org.alfresco.filesys.smb.server.notify.NotifyRequestList;
52 import org.alfresco.filesys.util.DataPacker;
53 import org.alfresco.filesys.util.StringList;
54 import org.apache.commons.logging.Log;
55 import org.apache.commons.logging.LogFactory;
56
57 /**
58  * SMB Session Class
59  *
60  * <p>
61  * The SMB server creates a server session object for each incoming session request.
62  * <p>
63  * The server session holds the context of a particular session, including the list of open files
64  * and active searches.
65  */

66 public class SMBSrvSession extends SrvSession implements Runnable JavaDoc
67 {
68     // Debug logging
69
private static Log logger = LogFactory.getLog("org.alfresco.smb.protocol");
70
71     // Define the default receive buffer size to allocate.
72

73     private static final int DefaultBufferSize = 0x010000 + RFCNetBIOSProtocol.HEADER_LEN;
74     private static final int LanManBufferSize = 8192;
75
76     // Default and maximum number of connection slots
77

78     private static final int DefaultConnections = 4;
79     private static final int MaxConnections = 16;
80
81     // Tree ids are 16bit values
82

83     private static final int TreeIdMask = 0x0000FFFF;
84
85     // Default and maximum number of search slots
86

87     private static final int DefaultSearches = 8;
88     private static final int MaxSearches = 256;
89
90     // Maximum multiplexed packets allowed (client can send up to this many SMBs before waiting for
91
// a response)
92
//
93
// Setting NTMaxMultiplexed to one will disable asynchronous notifications on the client
94

95     private static final int LanManMaxMultiplexed = 1;
96     private static final int NTMaxMultiplexed = 4;
97
98     // Maximum number of virtual circuits
99

100     private static final int MaxVirtualCircuits = 0;
101
102     // Packet handler used to send/receive SMB packets over a particular protocol
103

104     private PacketHandler m_pktHandler;
105
106     // Packet buffer for received data and received data length.
107

108     private byte[] m_buf;
109     private int m_rxlen;
110
111     // SMB packet used for response
112

113     private SMBSrvPacket m_smbPkt;
114
115     // Protocol handler for this session, depends upon the negotiated SMB dialect
116

117     private ProtocolHandler m_handler;
118
119     // SMB session state.
120

121     private int m_state = SMBSrvSessionState.NBSESSREQ;
122
123     // SMB dialect that this session has negotiated to use.
124

125     private int m_dialect = Dialect.Unknown;
126
127     // Callers NetBIOS name and target name
128

129     private String JavaDoc m_callerNBName;
130     private String JavaDoc m_targetNBName;
131
132     // Connected share list and next tree id
133

134     private Hashtable JavaDoc<Integer JavaDoc, TreeConnection> m_connections;
135     private int m_treeId;
136
137     // Active search list for this session
138

139     private SearchContext[] m_search;
140     private int m_searchCount;
141
142     // Active transaction details
143

144     private SrvTransactBuffer m_transact;
145
146     // Notify change requests and notifications pending flag
147

148     private NotifyRequestList m_notifyList;
149     private boolean m_notifyPending;
150
151     // Default SMB/CIFS flags anf flags2, ORed with the SMB packet flags/flags2 before sending a
152
// response to the client.
153

154     private int m_defFlags;
155     private int m_defFlags2;
156
157     // Asynchrnous response packet queue
158
//
159
// Contains SMB response packets that could not be sent due to SMB requests being processed. The
160
// asynchronous responses must be sent after any pending requests have been processed as the client may
161
// disconnect the session.
162

163     private Vector JavaDoc<SMBSrvPacket> m_asynchQueue;
164
165     // Maximum client buffer size and multiplex count
166

167     private int m_maxBufSize;
168     private int m_maxMultiplex;
169
170     // Client capabilities
171

172     private int m_clientCaps;
173
174     // Debug flag values
175

176     public static final int DBG_NETBIOS = 0x00000001; // NetBIOS layer
177
public static final int DBG_STATE = 0x00000002; // Session state changes
178
public static final int DBG_NEGOTIATE = 0x00000004; // Protocol negotiate phase
179
public static final int DBG_TREE = 0x00000008; // Tree connection/disconnection
180
public static final int DBG_SEARCH = 0x00000010; // File/directory search
181
public static final int DBG_INFO = 0x00000020; // Information requests
182
public static final int DBG_FILE = 0x00000040; // File open/close/info
183
public static final int DBG_FILEIO = 0x00000080; // File read/write
184
public static final int DBG_TRAN = 0x00000100; // Transactions
185
public static final int DBG_ECHO = 0x00000200; // Echo requests
186
public static final int DBG_ERROR = 0x00000400; // Errors
187
public static final int DBG_IPC = 0x00000800; // IPC$ requests
188
public static final int DBG_LOCK = 0x00001000; // Lock/unlock requests
189
public static final int DBG_PKTTYPE = 0x00002000; // Received packet type
190
public static final int DBG_DCERPC = 0x00004000; // DCE/RPC
191
public static final int DBG_STATECACHE = 0x00008000; // File state cache
192
public static final int DBG_NOTIFY = 0x00010000; // Asynchronous change notification
193
public static final int DBG_STREAMS = 0x00020000; // NTFS streams
194
public static final int DBG_SOCKET = 0x00040000; // NetBIOS/native SMB socket connections
195

196     /**
197      * Class constructor.
198      *
199      * @param handler Packet handler used to send/receive SMBs
200      * @param srv Server that this session is associated with.
201      */

202     public SMBSrvSession(PacketHandler handler, SMBServer srv)
203     {
204         super(-1, srv, handler.isProtocolName(), null);
205
206         // Set the packet handler
207

208         m_pktHandler = handler;
209
210         // Allocate a receive buffer
211

212         m_buf = new byte[DefaultBufferSize];
213         m_smbPkt = new SMBSrvPacket(m_buf);
214
215         // If this is a TCPIP SMB or Win32 NetBIOS session then bypass the NetBIOS session setup
216
// phase.
217

218         if (isProtocol() == SMBSrvPacket.PROTOCOL_TCPIP || isProtocol() == SMBSrvPacket.PROTOCOL_WIN32NETBIOS)
219         {
220
221             // Advance to the SMB negotiate dialect phase
222

223             setState(SMBSrvSessionState.SMBNEGOTIATE);
224
225             // Check if the client name is available
226

227             if (handler.hasClientName())
228                 m_callerNBName = handler.getClientName();
229         }
230     }
231
232     /**
233      * Return the session protocol type
234      *
235      * @return int
236      */

237     public final int isProtocol()
238     {
239         return m_pktHandler.isProtocol();
240     }
241
242     /**
243      * Add a new connection to this session. Return the allocated tree id for the new connection.
244      *
245      * @return int Allocated tree id (connection id).
246      * @param shrDev SharedDevice
247      */

248     protected int addConnection(SharedDevice shrDev) throws TooManyConnectionsException
249     {
250
251         // Check if the connection array has been allocated
252

253         if (m_connections == null)
254             m_connections = new Hashtable JavaDoc<Integer JavaDoc, TreeConnection>(DefaultConnections);
255
256         // Allocate an id for the tree connection
257

258         int treeId = 0;
259
260         synchronized (m_connections)
261         {
262
263             // Check if the tree connection table is full
264

265             if (m_connections.size() == MaxConnections)
266                 throw new TooManyConnectionsException();
267
268             // Find a free slot in the connection array
269

270             treeId = (m_treeId++ & TreeIdMask);
271             Integer JavaDoc key = new Integer JavaDoc(treeId);
272
273             while (m_connections.contains(key))
274             {
275
276                 // Try another tree id for the new connection
277

278                 treeId = (m_treeId++ & TreeIdMask);
279                 key = new Integer JavaDoc(treeId);
280             }
281
282             // Store the new tree connection
283

284             m_connections.put(key, new TreeConnection(shrDev));
285         }
286
287         // Return the allocated tree id
288

289         return treeId;
290     }
291
292     /**
293      * Allocate a slot in the active searches list for a new search.
294      *
295      * @return int Search slot index, or -1 if there are no more search slots available.
296      */

297     protected final int allocateSearchSlot()
298     {
299
300         // Check if the search array has been allocated
301

302         if (m_search == null)
303             m_search = new SearchContext[DefaultSearches];
304
305         // Find a free slot for the new search
306

307         int idx = 0;
308
309         while (idx < m_search.length && m_search[idx] != null)
310             idx++;
311
312         // Check if we found a free slot
313

314         if (idx == m_search.length)
315         {
316
317             // The search array needs to be extended, check if we reached the limit.
318

319             if (m_search.length >= MaxSearches)
320                 return -1;
321
322             // Extend the search array
323

324             SearchContext[] newSearch = new SearchContext[m_search.length * 2];
325             System.arraycopy(m_search, 0, newSearch, 0, m_search.length);
326             m_search = newSearch;
327         }
328
329         // Return the allocated search slot index
330

331         m_searchCount++;
332         return idx;
333     }
334
335     /**
336      * Cleanup any resources owned by this session, close files, searches and change notification
337      * requests.
338      */

339     protected final void cleanupSession()
340     {
341
342         // Debug
343

344         if (logger.isDebugEnabled() && hasDebug(DBG_STATE))
345             logger.debug("Cleanup session, searches=" + getSearchCount() + ", treeConns=" + getConnectionCount()
346                     + ", changeNotify=" + getNotifyChangeCount());
347
348         // Check if there are any active searches
349

350         if (m_search != null)
351         {
352
353             // Close all active searches
354

355             for (int idx = 0; idx < m_search.length; idx++)
356             {
357
358                 // Check if the current search slot is active
359

360                 if (m_search[idx] != null)
361                     deallocateSearchSlot(idx);
362             }
363
364             // Release the search context list, clear the search count
365

366             m_search = null;
367             m_searchCount = 0;
368         }
369
370         // Check if there are open tree connections
371

372         if (m_connections != null)
373         {
374
375             synchronized (m_connections)
376             {
377
378                 // Close all active tree connections
379

380                 Enumeration JavaDoc<TreeConnection> enm = m_connections.elements();
381
382                 while (enm.hasMoreElements())
383                 {
384
385                     // Get the current tree connection
386

387                     TreeConnection tree = enm.nextElement();
388                     DeviceInterface devIface = tree.getInterface();
389
390                     // Check if there are open files on the share
391

392                     if (tree.openFileCount() > 0)
393                     {
394
395                         // Close the open files, release locks
396

397                         for (int i = 0; i < tree.getFileTableLength(); i++)
398                         {
399
400                             // Get an open file
401

402                             NetworkFile curFile = tree.findFile(i);
403                             if (curFile != null && devIface instanceof DiskInterface)
404                             {
405
406                                 // Access the disk share interface
407

408                                 DiskInterface diskIface = (DiskInterface) devIface;
409
410                                 try
411                                 {
412
413                                     // Remove the file from the tree connection list
414

415                                     tree.removeFile(i, this);
416
417                                     // Close the file
418

419                                     diskIface.closeFile(this, tree, curFile);
420                                 }
421                                 catch (Exception JavaDoc ex)
422                                 {
423                                 }
424                             }
425                         }
426                     }
427                     // Inform the driver that the connection has been closed
428

429                     if (devIface != null)
430                         devIface.treeClosed(this, tree);
431                 }
432
433                 // Clear the tree connection list
434

435                 m_connections.clear();
436             }
437         }
438
439         // Commit, or rollback, any active user transaction
440

441         try
442         {
443             // Commit or rollback the transaction
444

445             endTransaction();
446         }
447         catch ( Exception JavaDoc ex)
448         {
449             // Debug
450

451             if ( logger.isDebugEnabled())
452                 logger.debug("Error committing transaction", ex);
453         }
454         
455         // Check if there are active change notification requests
456

457         if (m_notifyList != null && m_notifyList.numberOfRequests() > 0)
458         {
459
460             // Remove the notify requests from the associated device context notify list
461

462             for (int i = 0; i < m_notifyList.numberOfRequests(); i++)
463             {
464
465                 // Get the current change notification request and remove from the global notify
466
// list
467

468                 NotifyRequest curReq = m_notifyList.getRequest(i);
469                 curReq.getDiskContext().getChangeHandler().removeNotifyRequests(this);
470             }
471         }
472
473         // Delete any temporary shares that were created for this session
474

475         getSMBServer().deleteTemporaryShares(this);
476     }
477
478     /**
479      * Close the session socket
480      */

481     protected final void closeSocket()
482     {
483
484         // Indicate that the session is being shutdown
485

486         setShutdown(true);
487
488         // Close the packet handler
489

490         try
491         {
492             m_pktHandler.closeHandler();
493         }
494         catch (Exception JavaDoc ex)
495         {
496         }
497     }
498
499     /**
500      * Close the session
501      */

502     public final void closeSession()
503     {
504
505         // Call the base class
506

507         super.closeSession();
508
509         try
510         {
511
512             // Set the session into a hangup state and indicate that we have shutdown the session
513

514             setState(SMBSrvSessionState.NBHANGUP);
515             setShutdown(true);
516
517             // Close the packet handler
518

519             m_pktHandler.closeHandler();
520         }
521         catch (Exception JavaDoc ex)
522         {
523         }
524
525     }
526
527     /**
528      * Deallocate the specified search context/slot.
529      *
530      * @param ctxId int
531      */

532     protected final void deallocateSearchSlot(int ctxId)
533     {
534
535         // Check if the search array has been allocated and that the index is valid
536

537         if (m_search == null || ctxId >= m_search.length)
538             return;
539
540         // Close the search
541

542         if (m_search[ctxId] != null)
543             m_search[ctxId].closeSearch();
544
545         // Free the specified search context slot
546

547         m_searchCount--;
548         m_search[ctxId] = null;
549     }
550
551     /**
552      * Finalize, object is about to be garbage collected. Make sure resources are released.
553      */

554     public void finalize()
555     {
556
557         // Check if there are any active resources
558

559         cleanupSession();
560
561         // Make sure the socket is closed and deallocated
562

563         closeSocket();
564     }
565
566     /**
567      * Return the tree connection details for the specified tree id.
568      *
569      * @param treeId int
570      * @return TreeConnection
571      */

572     protected final TreeConnection findConnection(int treeId)
573     {
574
575         // Check if the tree id and connection array are valid
576

577         if (m_connections == null)
578             return null;
579
580         // Get the required tree connection details
581

582         return (TreeConnection) m_connections.get(new Integer JavaDoc(treeId));
583     }
584
585     /**
586      * Return the input/output metwork buffer for this session.
587      *
588      * @return byte[]
589      */

590     protected final byte[] getBuffer()
591     {
592         return m_buf;
593     }
594
595     /**
596      * Return the count of active connections for this session.
597      *
598      * @return int
599      */

600     public final int getConnectionCount()
601     {
602         return m_connections != null ? m_connections.size() : 0;
603     }
604
605     /**
606      * Return the default flags SMB header value
607      *
608      * @return int
609      */

610     public final int getDefaultFlags()
611     {
612         return m_defFlags;
613     }
614
615     /**
616      * Return the default flags2 SMB header value
617      *
618      * @return int
619      */

620     public final int getDefaultFlags2()
621     {
622         return m_defFlags2;
623     }
624
625     /**
626      * Return the count of active change notification requests
627      *
628      * @return int
629      */

630     public final int getNotifyChangeCount()
631     {
632         if (m_notifyList == null)
633             return 0;
634         return m_notifyList.numberOfRequests();
635     }
636
637     /**
638      * Return the client maximum buffer size
639      *
640      * @return int
641      */

642     public final int getClientMaximumBufferSize()
643     {
644         return m_maxBufSize;
645     }
646
647     /**
648      * Return the client maximum muliplexed requests
649      *
650      * @return int
651      */

652     public final int getClientMaximumMultiplex()
653     {
654         return m_maxMultiplex;
655     }
656
657     /**
658      * Return the client capability flags
659      *
660      * @return int
661      */

662     public final int getClientCapabilities()
663     {
664         return m_clientCaps;
665     }
666
667     /**
668      * Determine if the client has the specified capability enabled
669      *
670      * @param cap int
671      * @return boolean
672      */

673     public final boolean hasClientCapability(int cap)
674     {
675         if ((m_clientCaps & cap) != 0)
676             return true;
677         return false;
678     }
679
680     /**
681      * Return the SMB dialect type that the server/client have negotiated.
682      *
683      * @return int
684      */

685     public final int getNegotiatedSMBDialect()
686     {
687         return m_dialect;
688     }
689
690     /**
691      * Return the packet handler used by the session
692      *
693      * @return PacketHandler
694      */

695     public final PacketHandler getPacketHandler()
696     {
697         return m_pktHandler;
698     }
699
700     /**
701      * Return the receiver SMB packet.
702      *
703      * @return SMBSrvPacket
704      */

705     public final SMBSrvPacket getReceivePacket()
706     {
707         return m_smbPkt;
708     }
709
710     /**
711      * Return the remote NetBIOS name that was used to create the session.
712      *
713      * @return java.lang.String
714      */

715     public final String JavaDoc getRemoteNetBIOSName()
716     {
717         return m_callerNBName;
718     }
719
720     /**
721      * Check if the session has a target NetBIOS name
722      *
723      * @return boolean
724      */

725     public final boolean hasTargetNetBIOSName()
726     {
727         return m_targetNBName != null ? true : false;
728     }
729
730     /**
731      * Return the target NetBIOS name that was used to create the session
732      *
733      * @return String
734      */

735     public final String JavaDoc getTargetNetBIOSName()
736     {
737         return m_targetNBName;
738     }
739
740     /**
741      * Cehck if the clients remote address is available
742      *
743      * @return boolean
744      */

745     public final boolean hasRemoteAddress()
746     {
747         return m_pktHandler.hasRemoteAddress();
748     }
749
750     /**
751      * Return the client network address
752      *
753      * @return InetAddress
754      */

755     public final InetAddress JavaDoc getRemoteAddress()
756     {
757         return m_pktHandler.getRemoteAddress();
758     }
759
760     /**
761      * Return the search context for the specified search id.
762      *
763      * @param srchId int
764      * @return SearchContext
765      */

766     protected final SearchContext getSearchContext(int srchId)
767     {
768
769         // Check if the search array is valid and the search index is valid
770

771         if (m_search == null || srchId >= m_search.length)
772             return null;
773
774         // Return the required search context
775

776         return m_search[srchId];
777     }
778
779     /**
780      * Return the number of active tree searches.
781      *
782      * @return int
783      */

784     public final int getSearchCount()
785     {
786         return m_searchCount;
787     }
788
789     /**
790      * Return the server that this session is associated with.
791      *
792      * @return SMBServer
793      */

794     public final SMBServer getSMBServer()
795     {
796         return (SMBServer) getServer();
797     }
798
799     /**
800      * Return the server name that this session is associated with.
801      *
802      * @return java.lang.String
803      */

804     public final String JavaDoc getServerName()
805     {
806         return getSMBServer().getServerName();
807     }
808
809     /**
810      * Hangup the session.
811      *
812      * @param reason java.lang.String Reason the session is being closed.
813      */

814     private void hangupSession(String JavaDoc reason)
815     {
816
817         // Debug
818

819         if (logger.isDebugEnabled() && hasDebug(DBG_NETBIOS))
820             logger.debug("## Session closing - " + reason);
821
822         // Set the session into a NetBIOS hangup state
823

824         setState(SMBSrvSessionState.NBHANGUP);
825     }
826
827     /**
828      * Check if the Macintosh exteniosn SMBs are enabled
829      *
830      * @return boolean
831      */

832     public final boolean hasMacintoshExtensions()
833     {
834         return getSMBServer().getConfiguration().hasMacintoshExtensions();
835     }
836
837     /**
838      * Check if there is a change notification update pending
839      *
840      * @return boolean
841      */

842     public final boolean hasNotifyPending()
843     {
844         return m_notifyPending;
845     }
846
847     /**
848      * Set the change notify pending flag
849      *
850      * @param pend boolean
851      */

852     public final void setNotifyPending(boolean pend)
853     {
854         m_notifyPending = pend;
855     }
856
857     /**
858      * Set the client maximum buffer size
859      *
860      * @param maxBuf int
861      */

862     public final void setClientMaximumBufferSize(int maxBuf)
863     {
864         m_maxBufSize = maxBuf;
865     }
866
867     /**
868      * Set the client maximum multiplexed
869      *
870      * @param maxMpx int
871      */

872     public final void setClientMaximumMultiplex(int maxMpx)
873     {
874         m_maxMultiplex = maxMpx;
875     }
876
877     /**
878      * Set the client capability flags
879      *
880      * @param flags int
881      */

882     public final void setClientCapabilities(int flags)
883     {
884         m_clientCaps = flags;
885     }
886
887     /**
888      * Set the default flags value to be ORed with outgoing response packet flags
889      *
890      * @param flags int
891      */

892     public final void setDefaultFlags(int flags)
893     {
894         m_defFlags = flags;
895     }
896
897     /**
898      * Set the default flags2 value to be ORed with outgoing response packet flags2 field
899      *
900      * @param flags int
901      */

902     public final void setDefaultFlags2(int flags)
903     {
904         m_defFlags2 = flags;
905     }
906
907     /**
908      * Set the SMB packet
909      *
910      * @param pkt SMBSrvPacket
911      */

912     public final void setReceivePacket(SMBSrvPacket pkt)
913     {
914         m_smbPkt = pkt;
915         m_buf = pkt.getBuffer();
916     }
917
918     /**
919      * Store the seach context in the specified slot.
920      *
921      * @param slot Slot to store the search context.
922      * @param srch SearchContext
923      */

924     protected final void setSearchContext(int slot, SearchContext srch)
925     {
926
927         // Check if the search slot id is valid
928

929         if (m_search == null || slot > m_search.length)
930             return;
931
932         // Store the context
933

934         m_search[slot] = srch;
935     }
936
937     /**
938      * Set the session state.
939      *
940      * @param state int
941      */

942     protected void setState(int state)
943     {
944
945         // Debug
946

947         if (logger.isDebugEnabled() && hasDebug(DBG_STATE))
948             logger.debug("State changed to " + SMBSrvSessionState.getStateAsString(state));
949
950         // Change the session state
951

952         m_state = state;
953     }
954
955     /**
956      * Process the NetBIOS session request message, either accept the session request and send back
957      * a NetBIOS accept or reject the session and send back a NetBIOS reject and hangup the session.
958      */

959     protected void procNetBIOSSessionRequest() throws IOException JavaDoc, NetBIOSException
960     {
961
962         // Check if the received packet contains enough data for a NetBIOS session request packet.
963

964         NetBIOSPacket nbPkt = new NetBIOSPacket(m_buf);
965
966         if (m_rxlen < RFCNetBIOSProtocol.SESSREQ_LEN || nbPkt.getHeaderType() != RFCNetBIOSProtocol.SESSION_REQUEST)
967             throw new NetBIOSException("NBREQ Invalid packet");
968
969         // Do a few sanity checks on the received packet
970

971         if (m_buf[4] != (byte) 32 || m_buf[38] != (byte) 32)
972             throw new NetBIOSException("NBREQ Invalid NetBIOS name data");
973
974         // Extract the from/to NetBIOS encoded names, and convert to normal strings.
975

976         StringBuffer JavaDoc nbName = new StringBuffer JavaDoc(32);
977         for (int i = 0; i < 32; i++)
978             nbName.append((char) m_buf[5 + i]);
979         String JavaDoc toName = NetBIOSSession.DecodeName(nbName.toString());
980         toName = toName.trim();
981
982         nbName.setLength(0);
983         for (int i = 0; i < 32; i++)
984             nbName.append((char) m_buf[39 + i]);
985         String JavaDoc fromName = NetBIOSSession.DecodeName(nbName.toString());
986         fromName = fromName.trim();
987
988         // Debug
989

990         if (logger.isDebugEnabled() && hasDebug(DBG_NETBIOS))
991             logger.debug("NetBIOS CALL From " + fromName + " to " + toName);
992
993         // Check that the request is for this server
994

995         boolean forThisServer = false;
996
997         if (toName.compareTo(getServerName()) == 0 || toName.compareTo(NetBIOSName.SMBServer) == 0
998                 || toName.compareTo(NetBIOSName.SMBServer2) == 0 || toName.compareTo("*") == 0)
999         {
1000
1001            // Request is for this server
1002

1003            forThisServer = true;
1004        }
1005        else
1006        {
1007
1008            // Check if the caller is using an IP address
1009

1010            InetAddress JavaDoc[] srvAddr = getSMBServer().getServerAddresses();
1011            if (srvAddr != null)
1012            {
1013
1014                // Check for an address match
1015

1016                int idx = 0;
1017
1018                while (idx < srvAddr.length && forThisServer == false)
1019                {
1020
1021                    // Check the current IP address
1022

1023                    if (srvAddr[idx++].getHostAddress().compareTo(toName) == 0)
1024                        forThisServer = true;
1025                }
1026            }
1027        }
1028
1029        // If we did not find an address match then reject the session request
1030

1031        if (forThisServer == false)
1032            throw new NetBIOSException("NBREQ Called name is not this server (" + toName + ")");
1033
1034        // Debug
1035

1036        if (logger.isDebugEnabled() && hasDebug(DBG_NETBIOS))
1037            logger.debug("NetBIOS session request from " + fromName);
1038
1039        // Save the callers name and target name
1040

1041        m_callerNBName = fromName;
1042        m_targetNBName = toName;
1043
1044        // Set the remote client name
1045

1046        setRemoteName(fromName);
1047
1048        // Build a NetBIOS session accept message
1049

1050        nbPkt.setHeaderType(RFCNetBIOSProtocol.SESSION_ACK);
1051        nbPkt.setHeaderFlags(0);
1052        nbPkt.setHeaderLength(0);
1053
1054        // Output the NetBIOS session accept packet
1055

1056        m_pktHandler.writePacket(m_buf, 0, 4);
1057
1058        // Move the session to the SMB negotiate state
1059

1060        setState(SMBSrvSessionState.SMBNEGOTIATE);
1061    }
1062
1063    /**
1064     * Process an SMB dialect negotiate request.
1065     */

1066    protected void procSMBNegotiate() throws SMBSrvException, IOException JavaDoc
1067    {
1068
1069        // Create an SMB server packet using the receive buffer
1070

1071        m_smbPkt = new SMBSrvPacket(m_buf);
1072
1073        // Initialize the NetBIOS header
1074

1075        m_buf[0] = (byte) RFCNetBIOSProtocol.SESSION_MESSAGE;
1076
1077        // Check if the received packet looks like a valid SMB
1078

1079        if (m_smbPkt.getCommand() != PacketType.Negotiate || m_smbPkt.checkPacketIsValid(0, 2) == false)
1080        {
1081            sendErrorResponseSMB(SMBStatus.SRVUnrecognizedCommand, SMBStatus.ErrSrv);
1082            return;
1083        }
1084
1085        // Decode the data block into a list of requested SMB dialects
1086

1087        int dataPos = m_smbPkt.getByteOffset();
1088        int dataLen = m_smbPkt.getByteCount();
1089
1090        String JavaDoc diaStr = null;
1091        StringList dialects = new StringList();
1092
1093        while (dataLen > 0)
1094        {
1095
1096            // Decode an SMB dialect string from the data block, always ASCII strings
1097

1098            diaStr = DataPacker.getDataString(DataType.Dialect, m_buf, dataPos, dataLen, false);
1099            if (diaStr != null)
1100            {
1101
1102                // Add the dialect string to the list of requested dialects
1103

1104                dialects.addString(diaStr);
1105            }
1106            else
1107            {
1108
1109                // Invalid dialect block in the negotiate packet, send an error response and hangup
1110
// the session.
1111

1112                sendErrorResponseSMB(SMBStatus.SRVNonSpecificError, SMBStatus.ErrSrv);
1113                setState(SMBSrvSessionState.NBHANGUP);
1114                return;
1115            }
1116
1117            // Update the remaining data position and count
1118

1119            dataPos += diaStr.length() + 2; // data type and null
1120
dataLen -= diaStr.length() + 2;
1121        }
1122
1123        // Find the highest level SMB dialect that the server and client both support
1124

1125        DialectSelector dia = getSMBServer().getSMBDialects();
1126        int diaIdx = -1;
1127
1128        for (int i = 0; i < Dialect.Max; i++)
1129        {
1130
1131            // Check if the current dialect is supported by the server
1132

1133            if (dia.hasDialect(i))
1134            {
1135
1136                // Check if the client supports the current dialect. If the current dialect is a
1137
// higher level dialect than the currently nominated dialect, update the nominated
1138
// dialect index.
1139

1140                for (int j = 0; j < Dialect.SMB_PROT_MAXSTRING; j++)
1141                {
1142
1143                    // Check if the dialect string maps to the current dialect index
1144

1145                    if (Dialect.DialectType(j) == i && dialects.containsString(Dialect.DialectString(j)))
1146                    {
1147
1148                        // Update the selected dialect type, if the current dialect is a newer
1149
// dialect
1150

1151                        if (i > diaIdx)
1152                            diaIdx = i;
1153                    }
1154                }
1155            }
1156        }
1157
1158        // Debug
1159

1160        if (logger.isDebugEnabled() && hasDebug(DBG_NEGOTIATE))
1161        {
1162            if (diaIdx == -1)
1163                logger.debug("Failed to negotiate SMB dialect");
1164            else
1165                logger.debug("Negotiated SMB dialect - " + Dialect.DialectTypeString(diaIdx));
1166        }
1167
1168        // Check if we successfully negotiated an SMB dialect with the client
1169

1170        if (diaIdx != -1)
1171        {
1172
1173            // Store the negotiated SMB diialect type
1174

1175            m_dialect = diaIdx;
1176
1177            // Convert the dialect type to an index within the clients SMB dialect list
1178

1179            diaIdx = dialects.findString(Dialect.DialectTypeString(diaIdx));
1180
1181            // Allocate a protocol handler for the negotiated dialect, if we cannot get a protocol
1182
// handler then bounce the request.
1183

1184            m_handler = ProtocolFactory.getHandler(m_dialect);
1185            if (m_handler != null)
1186            {
1187
1188                // Debug
1189

1190                if (logger.isDebugEnabled() && hasDebug(DBG_NEGOTIATE))
1191                    logger.debug("Assigned protocol handler - " + m_handler.getClass().getName());
1192
1193                // Set the protocol handlers associated session
1194

1195                m_handler.setSession(this);
1196            }
1197            else
1198            {
1199
1200                // Could not get a protocol handler for the selected SMB dialect, indicate to the
1201
// client
1202
// that no suitable dialect available.
1203

1204                diaIdx = -1;
1205            }
1206        }
1207
1208        // Build the negotiate response SMB for Core dialect
1209

1210        if (m_dialect == -1 || m_dialect <= Dialect.CorePlus)
1211        {
1212
1213            // Core dialect negotiate response, or no valid dialect response
1214

1215            m_smbPkt.setParameterCount(1);
1216            m_smbPkt.setParameter(0, diaIdx);
1217            m_smbPkt.setByteCount(0);
1218
1219            m_smbPkt.setTreeId(0);
1220            m_smbPkt.setUserId(0);
1221        }
1222        else if (m_dialect <= Dialect.LanMan2_1)
1223        {
1224
1225            // We are using case sensitive pathnames and long file names
1226

1227            m_smbPkt.setFlags(SMBSrvPacket.FLG_CASELESS);
1228            m_smbPkt.setFlags2(SMBSrvPacket.FLG2_LONGFILENAMES);
1229
1230            // Access the authenticator for this server and determine if the server is in share or
1231
// user level
1232
// security mode.
1233

1234            SrvAuthenticator auth = getServer().getConfiguration().getAuthenticator();
1235            int secMode = 0;
1236
1237            if (auth != null)
1238            {
1239
1240                // Check if the server is in share or user level security mode
1241

1242                if (auth.getAccessMode() == SrvAuthenticator.USER_MODE)
1243                    secMode = 1;
1244
1245                // Check if encrypted passwords should be used by the client
1246

1247                if (auth.hasEncryptPasswords())
1248                    secMode += 2;
1249            }
1250
1251            // LanMan dialect negotiate response
1252

1253            m_smbPkt.setParameterCount(13);
1254            m_smbPkt.setParameter(0, diaIdx);
1255            m_smbPkt.setParameter(1, secMode); // Security mode, encrypt passwords
1256
m_smbPkt.setParameter(2, LanManBufferSize);
1257            m_smbPkt.setParameter(3, LanManMaxMultiplexed); // maximum multiplexed requests
1258
m_smbPkt.setParameter(4, MaxVirtualCircuits); // maximum number of virtual circuits
1259
m_smbPkt.setParameter(5, 0); // read/write raw mode support
1260

1261            // Create a session token, using the system clock
1262

1263            m_smbPkt.setParameterLong(6, (int) (System.currentTimeMillis() & 0xFFFFFFFF));
1264
1265            // Return the current server date/time
1266

1267            SMBDate srvDate = new SMBDate(System.currentTimeMillis());
1268            m_smbPkt.setParameter(8, srvDate.asSMBTime());
1269            m_smbPkt.setParameter(9, srvDate.asSMBDate());
1270
1271            // Server timezone offset from UTC
1272

1273            m_smbPkt.setParameter(10, getServer().getConfiguration().getTimeZoneOffset());
1274
1275            // Encryption key length
1276

1277            m_smbPkt.setParameter(11, 8); // Encryption key length
1278
m_smbPkt.setParameter(12, 0);
1279
1280            // Encryption key and primary domain string should be returned in the byte area
1281

1282            setChallengeKey(auth.getChallengeKey(this));
1283            int pos = m_smbPkt.getByteOffset();
1284            byte[] buf = m_smbPkt.getBuffer();
1285
1286            if (hasChallengeKey() == false)
1287            {
1288
1289                // Return a dummy encryption key
1290

1291                for (int i = 0; i < 8; i++)
1292                    buf[pos++] = 0;
1293            }
1294            else
1295            {
1296
1297                // Store the encryption key
1298

1299                byte[] key = getChallengeKey();
1300                for (int i = 0; i < key.length; i++)
1301                    buf[pos++] = key[i];
1302            }
1303
1304            // Set the local domain name
1305

1306            String JavaDoc domain = getServer().getConfiguration().getDomainName();
1307            if (domain != null)
1308                pos = DataPacker.putString(domain, buf, pos, true);
1309
1310            m_smbPkt.setByteCount(pos - m_smbPkt.getByteOffset());
1311
1312            m_smbPkt.setTreeId(0);
1313            m_smbPkt.setUserId(0);
1314        }
1315        else if (m_dialect == Dialect.NT)
1316        {
1317
1318            // We are using case sensitive pathnames and long file names
1319

1320            setDefaultFlags(SMBSrvPacket.FLG_CASELESS);
1321            setDefaultFlags2(SMBSrvPacket.FLG2_LONGFILENAMES + SMBSrvPacket.FLG2_UNICODE);
1322
1323            // Access the authenticator for this server and determine if the server is in share or
1324
// user level security mode.
1325

1326            SrvAuthenticator auth = getServer().getConfiguration().getAuthenticator();
1327            int secMode = 0;
1328
1329            if (auth != null)
1330            {
1331
1332                // Check if the server is in share or user level security mode
1333

1334                if (auth.getAccessMode() == SrvAuthenticator.USER_MODE)
1335                    secMode = 1;
1336
1337                // Check if encrypted passwords should be used by the client
1338

1339                if (auth.hasEncryptPasswords())
1340                    secMode += 2;
1341            }
1342
1343            // NT dialect negotiate response
1344

1345            NTParameterPacker nt = new NTParameterPacker(m_smbPkt.getBuffer());
1346
1347            m_smbPkt.setParameterCount(17);
1348            nt.packWord(diaIdx); // selected dialect index
1349
nt.packByte(secMode); // security mode
1350
nt.packWord(NTMaxMultiplexed); // maximum multiplexed requests
1351
// setting to 1 will disable change notify requests from the client
1352
nt.packWord(MaxVirtualCircuits); // maximum number of virtual circuits
1353

1354            int maxBufSize = m_smbPkt.getBuffer().length - RFCNetBIOSProtocol.HEADER_LEN;
1355            nt.packInt(maxBufSize);
1356
1357            nt.packInt(0); // maximum raw size
1358

1359            // Create a session token, using the system clock
1360

1361            nt.packInt((int) (System.currentTimeMillis() & 0xFFFFFFFFL));
1362
1363            // Set server capabilities
1364

1365            nt.packInt(Capability.Unicode + Capability.RemoteAPIs + Capability.NTSMBs + Capability.NTFind
1366                    + Capability.NTStatus + Capability.LargeFiles + Capability.LargeRead + Capability.LargeWrite);
1367
1368            // Return the current server date/time, and timezone offset
1369

1370            long srvTime = NTTime.toNTTime(new java.util.Date JavaDoc(System.currentTimeMillis()));
1371
1372            nt.packLong(srvTime);
1373            nt.packWord(getServer().getConfiguration().getTimeZoneOffset());
1374
1375            // Encryption key length
1376

1377            nt.packByte(8); // encryption key length
1378

1379            // Encryption key and primary domain string should be returned in the byte area
1380

1381            setChallengeKey(auth.getChallengeKey(this));
1382
1383            int pos = m_smbPkt.getByteOffset();
1384            byte[] buf = m_smbPkt.getBuffer();
1385
1386            if (hasChallengeKey() == false)
1387            {
1388
1389                // Return a dummy encryption key
1390

1391                for (int i = 0; i < 8; i++)
1392                    buf[pos++] = 0;
1393            }
1394            else
1395            {
1396
1397                // Store the encryption key
1398

1399                byte[] key = getChallengeKey();
1400
1401                for (int i = 0; i < key.length; i++)
1402                    buf[pos++] = key[i];
1403            }
1404
1405            // Pack the local domain name
1406

1407            String JavaDoc domain = getServer().getConfiguration().getDomainName();
1408            if (domain != null)
1409                pos = DataPacker.putUnicodeString(domain, buf, pos, true);
1410
1411            // Pack the server name
1412

1413            pos = DataPacker.putUnicodeString(getServerName(), buf, pos, true);
1414
1415            // Set the packet length
1416

1417            m_smbPkt.setByteCount(pos - m_smbPkt.getByteOffset());
1418
1419            m_smbPkt.setFlags( getDefaultFlags());
1420            m_smbPkt.setFlags2( getDefaultFlags2());
1421            
1422            m_smbPkt.setTreeId(0);
1423            m_smbPkt.setUserId(0);
1424        }
1425
1426        // Make sure the response flag is set
1427

1428        if (m_smbPkt.isResponse() == false)
1429            m_smbPkt.setFlags(m_smbPkt.getFlags() + SMBPacket.FLG_RESPONSE);
1430
1431        // Send the negotiate response
1432

1433        m_pktHandler.writePacket(m_smbPkt, m_smbPkt.getLength());
1434
1435        // Check if the negotiated SMB dialect supports the session setup command, if not then
1436
// bypass
1437
// the session setup phase.
1438

1439        if (m_dialect == -1)
1440            setState(SMBSrvSessionState.NBHANGUP);
1441        else if (Dialect.DialectSupportsCommand(m_dialect, PacketType.SessionSetupAndX))
1442            setState(SMBSrvSessionState.SMBSESSSETUP);
1443        else
1444            setState(SMBSrvSessionState.SMBSESSION);
1445
1446        // If a dialect was selected inform the server that the session has been opened
1447

1448        if (m_dialect != -1)
1449            getSMBServer().sessionOpened(this);
1450    }
1451
1452    /**
1453     * Remove the specified tree connection from the active connection list.
1454     *
1455     * @param treeId int
1456     */

1457    protected void removeConnection(int treeId)
1458    {
1459
1460        // Check if the tree id is valid
1461

1462        if (m_connections == null)
1463            return;
1464
1465        // Close the connection and remove from the connection list
1466

1467        synchronized (m_connections)
1468        {
1469
1470            // Get the connection
1471

1472            Integer JavaDoc key = new Integer JavaDoc(treeId);
1473            TreeConnection tree = (TreeConnection) m_connections.get(key);
1474
1475            // Close the connection, release resources
1476

1477            if (tree != null)
1478            {
1479
1480                // Close the connection
1481

1482                tree.closeConnection(this);
1483
1484                // Remove the connection from the connection list
1485

1486                m_connections.remove(key);
1487            }
1488        }
1489    }
1490
1491    /**
1492     * Start the SMB server session in a seperate thread.
1493     */

1494    public void run()
1495    {
1496        try
1497        {
1498            // Debug
1499

1500            if (logger.isDebugEnabled() && hasDebug(SMBSrvSession.DBG_NEGOTIATE))
1501                logger.debug("Server session started");
1502
1503            // The server session loops until the NetBIOS hangup state is set.
1504

1505            while (m_state != SMBSrvSessionState.NBHANGUP)
1506            {
1507
1508                // Set the current receive length to -1 to indicate that the session thread is not
1509
// currently processing an SMB packet. This is used by the asynchronous response code
1510
// to determine when it can send the response.
1511

1512                m_rxlen = -1;
1513
1514                // Wait for a data packet
1515

1516                m_rxlen = m_pktHandler.readPacket(m_smbPkt);
1517
1518                // Check for an empty packet
1519

1520                if (m_rxlen == 0)
1521                    continue;
1522
1523                // Check if there is no more data, the other side has dropped the connection
1524

1525                if (m_rxlen == -1)
1526                {
1527                    hangupSession("Remote disconnect");
1528                    continue;
1529                }
1530
1531                // Store the received data length
1532

1533                m_smbPkt.setReceivedLength(m_rxlen);
1534
1535                // Update the request count
1536

1537                m_reqCount++;
1538                
1539                // Process the received packet
1540

1541                switch (m_state)
1542                {
1543
1544                // NetBIOS session request pending
1545

1546                case SMBSrvSessionState.NBSESSREQ:
1547                    procNetBIOSSessionRequest();
1548                    break;
1549
1550                // SMB dialect negotiate
1551

1552                case SMBSrvSessionState.SMBNEGOTIATE:
1553                    procSMBNegotiate();
1554                    break;
1555
1556                // SMB session setup
1557

1558                case SMBSrvSessionState.SMBSESSSETUP:
1559                    m_handler.runProtocol();
1560                    break;
1561
1562                // SMB session main request processing
1563

1564                case SMBSrvSessionState.SMBSESSION:
1565
1566                    // Run the main protocol handler
1567

1568                    runHandler();
1569                    break;
1570
1571                } // end switch session state
1572

1573                // Commit, or rollback, any active user transaction
1574

1575                try
1576                {
1577                    // Commit or rollback the transaction
1578

1579                    endTransaction();
1580                }
1581                catch ( Exception JavaDoc ex)
1582                {
1583                    // Debug
1584

1585                    if ( logger.isDebugEnabled())
1586                        logger.debug("Error committing transaction", ex);
1587                }
1588
1589                // Give up the CPU
1590

1591                Thread.yield();
1592
1593            } // end while state
1594
}
1595        catch (SocketException JavaDoc ex)
1596        {
1597
1598            // DEBUG
1599

1600            logger.error("Socket closed by remote client");
1601        }
1602        catch (Exception JavaDoc ex)
1603        {
1604
1605            // Output the exception details
1606

1607            if (isShutdown() == false)
1608                logger.error("Closing session due to exception", ex);
1609        }
1610        catch (Throwable JavaDoc ex)
1611        {
1612            logger.error("Closing session due to throwable", ex);
1613        }
1614        finally
1615        {
1616            // If there is an active transaction then roll it back
1617

1618            if ( hasUserTransaction())
1619            {
1620                try
1621                {
1622                    getUserTransaction().rollback();
1623                }
1624                catch (Exception JavaDoc ex)
1625                {
1626                    logger.warn("Failed to rollback transaction", ex);
1627                }
1628            }
1629        }
1630
1631        // Cleanup the session, make sure all resources are released
1632

1633        cleanupSession();
1634
1635        // Debug
1636

1637        if (logger.isDebugEnabled() && hasDebug(DBG_STATE))
1638            logger.debug("Server session closed");
1639
1640        // Close the session
1641

1642        closeSocket();
1643
1644        // Notify the server that the session has closed
1645

1646        getSMBServer().sessionClosed(this);
1647    }
1648
1649    /**
1650     * Handle a session message, receive all data and run the SMB protocol handler.
1651     */

1652    protected final void runHandler() throws IOException JavaDoc, SMBSrvException, TooManyConnectionsException
1653    {
1654
1655        // Make sure we received at least a NetBIOS header
1656

1657        if (m_rxlen < NetBIOSPacket.MIN_RXLEN)
1658            return;
1659
1660        // DEBUG
1661

1662        if (logger.isDebugEnabled() && hasDebug(DBG_PKTTYPE))
1663            logger.debug("Rx packet type - " + m_smbPkt.getPacketTypeString() + ", SID=" + m_smbPkt.getSID());
1664
1665        // Call the protocol handler
1666

1667        if (m_handler.runProtocol() == false)
1668        {
1669
1670            // The sessions protocol handler did not process the request, return an unsupported
1671
// SMB error status.
1672

1673            sendErrorResponseSMB(SMBStatus.SRVNotSupported, SMBStatus.ErrSrv);
1674        }
1675
1676        // Check if there are any pending asynchronous response packets
1677

1678        while (hasAsynchResponse())
1679        {
1680
1681            // Remove the current asynchronous response SMB packet and send to the client
1682

1683            SMBSrvPacket asynchPkt = removeFirstAsynchResponse();
1684            sendResponseSMB(asynchPkt, asynchPkt.getLength());
1685
1686            // DEBUG
1687

1688            if (logger.isDebugEnabled() && hasDebug(DBG_NOTIFY))
1689                logger.debug("Sent queued asynch response type=" + asynchPkt.getPacketTypeString() + ", mid="
1690                        + asynchPkt.getMultiplexId() + ", pid=" + asynchPkt.getProcessId());
1691        }
1692    }
1693
1694    /**
1695     * Send an SMB response
1696     *
1697     * @param pkt SMBSrvPacket
1698     * @exception IOException
1699     */

1700    public final void sendResponseSMB(SMBSrvPacket pkt) throws IOException JavaDoc
1701    {
1702        sendResponseSMB(pkt, pkt.getLength());
1703    }
1704
1705    /**
1706     * Send an SMB response
1707     *
1708     * @param pkt SMBSrvPacket
1709     * @param len int
1710     * @exception IOException
1711     */

1712    public synchronized final void sendResponseSMB(SMBSrvPacket pkt, int len) throws IOException JavaDoc
1713    {
1714
1715        // Make sure the response flag is set
1716

1717        if (pkt.isResponse() == false)
1718            pkt.setFlags(pkt.getFlags() + SMBSrvPacket.FLG_RESPONSE);
1719
1720        // Add default flags/flags2 values
1721

1722        pkt.setFlags(pkt.getFlags() | getDefaultFlags());
1723
1724        // Mask out certain flags that the client may have sent
1725

1726        int flags2 = pkt.getFlags2() | getDefaultFlags2();
1727        flags2 &= ~(SMBPacket.FLG2_EXTENDEDATTRIB + SMBPacket.FLG2_EXTENDNEGOTIATE + SMBPacket.FLG2_DFSRESOLVE + SMBPacket.FLG2_SECURITYSIGS);
1728
1729        pkt.setFlags2(flags2);
1730
1731        // Send the response packet
1732

1733        m_pktHandler.writePacket(pkt, len);
1734        m_pktHandler.flushPacket();
1735    }
1736
1737    /**
1738     * Send a success response SMB
1739     *
1740     * @exception IOException If a network error occurs
1741     */

1742    public final void sendSuccessResponseSMB() throws IOException JavaDoc
1743    {
1744
1745        // Make sure the response flag is set
1746

1747        if (m_smbPkt.isResponse() == false)
1748            m_smbPkt.setFlags(m_smbPkt.getFlags() + SMBSrvPacket.FLG_RESPONSE);
1749
1750        // Add default flags/flags2 values
1751

1752        m_smbPkt.setFlags(m_smbPkt.getFlags() | getDefaultFlags());
1753        m_smbPkt.setFlags2(m_smbPkt.getFlags2() | getDefaultFlags2());
1754
1755        // Clear the parameter and byte counts
1756

1757        m_smbPkt.setParameterCount(0);
1758        m_smbPkt.setByteCount(0);
1759
1760        if (m_smbPkt.isLongErrorCode())
1761            m_smbPkt.setLongErrorCode(SMBStatus.NTSuccess);
1762        else
1763        {
1764            m_smbPkt.setErrorClass(SMBStatus.Success);
1765            m_smbPkt.setErrorCode(SMBStatus.Success);
1766        }
1767
1768        // Return the success response to the client
1769

1770        sendResponseSMB(m_smbPkt, m_smbPkt.getLength());
1771    }
1772
1773    /**
1774     * Send an error response SMB. The returned code depends on the client long error code flag
1775     * setting.
1776     *
1777     * @param ntCode 32bit error code
1778     * @param stdCode Standard error code
1779     * @param StdClass Standard error class
1780     */

1781    public final void sendErrorResponseSMB(int ntCode, int stdCode, int stdClass) throws java.io.IOException JavaDoc
1782    {
1783
1784        // Check if long error codes are required by the client
1785

1786        if (m_smbPkt.isLongErrorCode())
1787        {
1788
1789            // Return the long/NT status code
1790

1791            sendErrorResponseSMB(ntCode, SMBStatus.NTErr);
1792        }
1793        else
1794        {
1795
1796            // Return the standard/DOS error code
1797

1798            sendErrorResponseSMB(stdCode, stdClass);
1799        }
1800    }
1801
1802    /**
1803     * Send an error response SMB.
1804     *
1805     * @param errCode int Error code.
1806     * @param errClass int Error class.
1807     */

1808    public final void sendErrorResponseSMB(int errCode, int errClass) throws java.io.IOException JavaDoc
1809    {
1810
1811        // Make sure the response flag is set
1812

1813        if (m_smbPkt.isResponse() == false)
1814            m_smbPkt.setFlags(m_smbPkt.getFlags() + SMBSrvPacket.FLG_RESPONSE);
1815
1816        // Set the error code and error class in the response packet
1817

1818        m_smbPkt.setParameterCount(0);
1819        m_smbPkt.setByteCount(0);
1820
1821        // Add default flags/flags2 values
1822

1823        m_smbPkt.setFlags(m_smbPkt.getFlags() | getDefaultFlags());
1824        m_smbPkt.setFlags2(m_smbPkt.getFlags2() | getDefaultFlags2());
1825
1826        // Check if the error is a NT 32bit error status
1827

1828        if (errClass == SMBStatus.NTErr)
1829        {
1830
1831            // Enable the long error status flag
1832

1833            if (m_smbPkt.isLongErrorCode() == false)
1834                m_smbPkt.setFlags2(m_smbPkt.getFlags2() + SMBSrvPacket.FLG2_LONGERRORCODE);
1835
1836            // Set the NT status code
1837

1838            m_smbPkt.setLongErrorCode(errCode);
1839        }
1840        else
1841        {
1842
1843            // Disable the long error status flag
1844

1845            if (m_smbPkt.isLongErrorCode() == true)
1846                m_smbPkt.setFlags2(m_smbPkt.getFlags2() - SMBSrvPacket.FLG2_LONGERRORCODE);
1847
1848            // Set the error status/class
1849

1850            m_smbPkt.setErrorCode(errCode);
1851            m_smbPkt.setErrorClass(errClass);
1852        }
1853
1854        // Return the error response to the client
1855

1856        sendResponseSMB(m_smbPkt, m_smbPkt.getLength());
1857
1858        // Debug
1859

1860        if (logger.isDebugEnabled() && hasDebug(DBG_ERROR))
1861            logger.debug("Error : Cmd = " + m_smbPkt.getPacketTypeString() + " - "
1862                    + SMBErrorText.ErrorString(errClass, errCode));
1863    }
1864
1865    /**
1866     * Send, or queue, an asynchronous response SMB
1867     *
1868     * @param pkt SMBSrvPacket
1869     * @param len int
1870     * @return true if the packet was sent, or false if it was queued
1871     * @exception IOException If an I/O error occurs
1872     */

1873    public final boolean sendAsynchResponseSMB(SMBSrvPacket pkt, int len) throws IOException JavaDoc
1874    {
1875
1876        // Check if there is an SMB currently being processed or pending data from the client
1877

1878        boolean sts = false;
1879
1880        if (m_rxlen == -1 && m_pktHandler.availableBytes() == 0)
1881        {
1882
1883            // Send the asynchronous response immediately
1884

1885            sendResponseSMB(pkt, len);
1886            m_pktHandler.flushPacket();
1887
1888            // Indicate that the SMB response has been sent
1889

1890            sts = true;
1891        }
1892        else
1893        {
1894
1895            // Queue the packet to send out when current SMB requests have been processed
1896

1897            queueAsynchResponseSMB(pkt);
1898        }
1899
1900        // Return the sent/queued status
1901

1902        return sts;
1903    }
1904
1905    /**
1906     * Queue an asynchronous response SMB for sending when current SMB requests have been processed.
1907     *
1908     * @param pkt SMBSrvPacket
1909     */

1910    protected final synchronized void queueAsynchResponseSMB(SMBSrvPacket pkt)
1911    {
1912
1913        // Check if the asynchronous response queue has been allocated
1914

1915        if (m_asynchQueue == null)
1916        {
1917
1918            // Allocate the asynchronous response queue
1919

1920            m_asynchQueue = new Vector JavaDoc<SMBSrvPacket>();
1921        }
1922
1923        // Add the SMB response packet to the queue
1924

1925        m_asynchQueue.addElement(pkt);
1926    }
1927
1928    /**
1929     * Check if there are any asynchronous requests queued
1930     *
1931     * @return boolean
1932     */

1933    protected final synchronized boolean hasAsynchResponse()
1934    {
1935
1936        // Check if the queue is valid
1937

1938        if (m_asynchQueue != null && m_asynchQueue.size() > 0)
1939            return true;
1940        return false;
1941    }
1942
1943    /**
1944     * Remove an asynchronous response packet from the head of the list
1945     *
1946     * @return SMBSrvPacket
1947     */

1948    protected final synchronized SMBSrvPacket removeFirstAsynchResponse()
1949    {
1950
1951        // Check if there are asynchronous response packets queued
1952

1953        if (m_asynchQueue == null || m_asynchQueue.size() == 0)
1954            return null;
1955
1956        // Return the SMB packet from the head of the queue
1957

1958        return m_asynchQueue.remove(0);
1959    }
1960
1961    /**
1962     * Find the notify request with the specified ids
1963     *
1964     * @param mid int
1965     * @param tid int
1966     * @param uid int
1967     * @param pid int
1968     * @return NotifyRequest
1969     */

1970    public final NotifyRequest findNotifyRequest(int mid, int tid, int uid, int pid)
1971    {
1972
1973        // Check if the local notify list is valid
1974

1975        if (m_notifyList == null)
1976            return null;
1977
1978        // Find the matching notify request
1979

1980        return m_notifyList.findRequest(mid, tid, uid, pid);
1981    }
1982
1983    /**
1984     * Find an existing notify request for the specified directory and filter
1985     *
1986     * @param dir NetworkFile
1987     * @param filter int
1988     * @param watchTree boolean
1989     * @return NotifyRequest
1990     */

1991    public final NotifyRequest findNotifyRequest(NetworkFile dir, int filter, boolean watchTree)
1992    {
1993
1994        // Check if the local notify list is valid
1995

1996        if (m_notifyList == null)
1997            return null;
1998
1999        // Find the matching notify request
2000

2001        return m_notifyList.findRequest(dir, filter, watchTree);
2002    }
2003
2004    /**
2005     * Add a change notification request
2006     *
2007     * @param req NotifyRequest
2008     * @param ctx DiskDeviceContext
2009     */

2010    public final void addNotifyRequest(NotifyRequest req, DiskDeviceContext ctx)
2011    {
2012
2013        // Check if the local notify list has been allocated
2014

2015        if (m_notifyList == null)
2016            m_notifyList = new NotifyRequestList();
2017
2018        // Add the request to the local list and the shares global list
2019

2020        m_notifyList.addRequest(req);
2021        ctx.addNotifyRequest(req);
2022    }
2023
2024    /**
2025     * Remove a change notification request
2026     *
2027     * @param req NotifyRequest
2028     */

2029    public final void removeNotifyRequest(NotifyRequest req)
2030    {
2031
2032        // Check if the local notify list has been allocated
2033

2034        if (m_notifyList == null)
2035            return;
2036
2037        // Remove the request from the local list and the shares global list
2038

2039        m_notifyList.removeRequest(req);
2040        if (req.getDiskContext() != null)
2041            req.getDiskContext().removeNotifyRequest(req);
2042    }
2043
2044    /**
2045     * Check if there is an active transaction
2046     *
2047     * @return boolean
2048     */

2049    protected final boolean hasTransaction()
2050    {
2051        return m_transact != null ? true : false;
2052    }
2053
2054    /**
2055     * Return the active transaction buffer
2056     *
2057     * @return TransactBuffer
2058     */

2059    protected final SrvTransactBuffer getTransaction()
2060    {
2061        return m_transact;
2062    }
2063
2064    /**
2065     * Set the active transaction buffer
2066     *
2067     * @param buf TransactBuffer
2068     */

2069    protected final void setTransaction(SrvTransactBuffer buf)
2070    {
2071        m_transact = buf;
2072    }
2073}
Popular Tags