
Wed Mar 15 15:39:15 EST 2000

The netbios name service is complete. I have changed the package name to jcifs and released it as 0.1. No real significant changes. Just did a lot of testing, documentation, etc. See README, javadoc, and the example for details.

I'm checking this in now.

http://racer-x.nts.umn.edu/jcifs/src

Later,
Mike

Mon Jan 17 22:03:21 EST 2000

The focus has changed a little. I am now gearing for the client. I
will take all server oriented stuff and put it on CVS as a tgz later. I
have stripped down the current code and consolodated a few classes. The
netbios name service is pretty much done. I have a few more things to
do so this is just a prelinary checkin.

All files in the mba package:

mba/ChangeLog
mba/netbios/
	ClientNameServicePacket.java
	Log.java
	Name.java
	NbtAddress.java
	NbtConfig.java
	NbtNameServiceClient.java
	UnknownNbtHostException.java
mba/util/
	Log.java
	LogWriter.java
	MultiDatagramSocket.java
	PacketEvent.java
	PacketEventQueue.java
	README.MultiDatagramSocket

The interface is brain deadingly simple.

	import mba.netbios.NbtAddress;

	try {
		InetAddress addr =
			NbtAddress.getByName( "fred" ).getInetAddress();
		// now you have the ip
	} catch( Exception x ) {
	}

Other methods include:

	NbtAddress.getLocalHost() // handy for getting local netbios hostname
	NbtAddress.getAllByName() // lookup netbios group names
	NbtAddress.getHostName()  // do reverse lookups like with Inetaddress
	NbtAddress.getAddress()
	NbtAddress.getHostAddress()
	...

As you can see it is like the java.net.InetAddress class. In fact I pretty
much ripped off Java 2's InetAddress class byte for byte :-) I did add a
method called getAllByAddress( String dotQuad ) for the node status
call. There may be things that need to be set however it will try it's
best to figure out what was not defined. I have created a separate class
for these settings:

	NbtConfig.setNameServer( InetAddress nameserver )
	NbtConfig.setBroadcastAddress( InetAddress bCastAddress )
	NbtConfig.setCachePolicy( 123 )
	...

I spend quite a bit of time working on a syslog like logging scheme. Right
now to log info you can do:

	mba.util.Log.setMask( Log.ALL
					- Log.HEX_DUMPS
					- mba.netbios.Log.PACKET_DIAGRAMS );

The constants are integers that are simply added or subtracted together to
define whats logged. You can also set the Writer or OutputStream like so:

	mba.util.Log.setPrintWriter( new FileWriter( "mylog.log" ));

It would be nice to be able to define separate streams with different
masks. I would really like to hear peoples opinions on logging.

Everything is thread safe of course and multi-threaded apps can service
requests concurrently(not added quite yet), meaning if you do a query and
it takes a while to return(times out) another thread can send a separate
query and receive an answer before the first finishes(all on the same
socket too). Also the client that NbtAddress calls is public. If for some
reason you wish to run multiple clients( all querying different WINS
servers perhaps) you can instantiate NbtNameServiceClient directly. It
is meant to provide a lower level of access and control. There are no
assumtions made about caching and so fourth.

I think I have the technique down now so the transport layer should come
pretty soon. Then it's on to SMB!.

Sun Nov 7  23:56:00 EDT 1999

I have added three classes and placed them in the mba/util directory. As
repeated in my post on the list processor:

I believe I have finally settled on a multithreaded packet handling
mechanism called a MultiDatagramSocket:

MultiDatagramSocket employs a simple linked list queuing mechanism and an
internal thread dedicated to reading from the socket to allow multiple
threads to concurrently send and receive datagram packets on the same port
at rates independent from one another.

There are three classes that encapsulate this functionality:

	mba.util.MultiDatagramSocket.java
	mba.util.PacketEventQueue.java
	mba.util.PacketEvent.java

MultiDatagramSocket is, at first glance, almost identical to
java.net.DatagramSocket but instead of calling receive( DatagramPacket) you
obtain a PacketEventQueue by calling createPacketEventQueue() and read in
PacketEvents at leisure by calling getNextPacketEvent() on the
PacketEventQueue. PacketEvent encapsulates the DatagramPacket, the reception
time and is clonable.  The getNextPacketEvent() method will block until a
packet is received if there are no PacketEvents in the queue.

MultiDatagramSocket is a general purpose socket handling class and has
nothing to do with netbios other than the fact that it will work very well
for the name service and for perhaps the datagram service. The only thing
you might need to change for a given application is the
MAX_DATAGRAM_LENGTH(576 bytes by default). The socket resets the
DatagramPackets length to this size before each read. So if you using
packets greater in size than 576 you will need to change this one variable.

Any number of PacketEventQueues can be created and each queue can have any
number of PacketEvents. Both are linked list data structures(linked list of
linked lists). It is totally thread safe. All incoming packets are enqueued
in each PacketEventQueue so you don't have to worry about stealing another
processes packets. This is a highly flexible model and provides great
abstraction. Also, you can start and stop MultiDatagramSocket any number of
times without worrying about reinstantiating. If stop is called, any
PacketEventQueue owners who are blocked on getNextPacketEvent will be
released by throwing an InterruptedException.

These classes have been tested quite a bit. My post about the properties of
java.net.DatagramSocket actually used a MultiDatagramSocket. Those tests did
not test using multiple PacketEventQueues or dynamically adding and removing
PacketEventQueues while selectively retrieving PacketEvents although I have
conducted such tests and I believe MultiDatagramSocket will work as
advertised.

Details:

I decided against using the classic AWT event based model I discussed
previously. It was just wrong for this. It's embarrassing to think of how
much code I went through to end up with this. Altogether these classes are
only 248 lines of code(doh!). I guess it could not have turned out better
though.

Basically the way this works is there is one internal thread that does
nothing more than call receive on a DatagramSocket. When a packet comes in
it notes the time and creates a PacketEvent object. It then clones the
PacketEvent once and adds it to each node of a linked list of
PacketEventQueues(if there are any). PakcetEvents are stored as a linked
list too. So coupled with the PacketEventQueue, the data structure can be
envisioned as a linked list of linked lists. Then it goes back to reading
the socket again. At no time is there any blocking so only one thread is
needed to read from the socket. Even though some methods are synchronized
you can follow the locks and find there is no blocking.

After the MultiDatagramSocket is instantiated it must be started by calling
start() although this is not necessary if the socket is only being used to
send(but then why would you need a MultiDatagramSocket in the first place).
Then other threads can obtain PacketEventQueues with
createPacketEventQueue(). Actually you don't have to start the socket before
creating PacketEventQueues but of course they will not receive any packets
until you do so. As soon as a thread creates a new PacketEventQueue it is
currently queuing packets. So if the thread chooses not to call
getNextPacketEvent() for a while it may get a back log of packets. This is
probably not a good idea as there are no limitations on the size of the
number of PacketEvents in the PacketEventQueue and therefore an "Out of
Memory" VM error could occur if packets are not read and discarded or
cleared with the clear() method. Incidentally you can also call getSize()
and isEmpty() to find out the contents without actually reading from the
socket. Try that with DatagramSocket!.

Important Note: When the internal thread enqueues an incoming packet is
clones it only once so that when another packet comes in the data is not
overwritten in the queues. But the data(DatagramPacket, it's buffer, and so
on) are not cloned for entry into each queue. In other words, with each
incoming packet, the same PacketEvent object is queued to all
PacketEventQueues. So you CANNOT MODIFY the data of a PacketEvent without
cloning it first or other PacketEventQueues will observe the changes. This
is one reason why PacketEvent is clonable. This was done for purposes of
efficiency. I have found that in practice packets are simply examined and
not modified. So if you want to recycle a packet for it's data just clone it
first. Still pretty efficient and flexible. Everybody has a direct line on
the socket.

So you can have separate processes all working on there own
PacketEventQueues. Or if you have one process that is slow or blocks quite a
bit but needs to process packets faster you can have multiple threads
reading from the same PacketEventQueue. Again all structures are totally
thread safe. As an example lets say you have a server that has several
different functions. You might have one thread servicing name queries(or
multiple threads operating on the same PacketEventQueue) while another
thread simply logs packet events. Even if the queue gets backed up you still
have the precise time that it arrived through getTime(). You might
simultaneously have a watchdog thread that just decodes packets in some
totally inefficient way. Each process can process packets as quickly or as
slowly as they wish. If a process is slow, presumably the load would dip
long enough for any one process to catch up and clean out it's queue. As a
precaution you might periodically call getSize() and then clear() if there
are too many packets in the queue.

I have not checked this in yet but I will very shortly. I think it will be
here:

http://racer-x.nts.umn.edu/jcifs/src/mba/util

Later,
Mike


=========================================================================


Sun Sep 26 22:49:30 EDT 1999

The mba.netbios package contains classes for encoding/decoding
NetBIOS over TCP name service packets as well as the beginnings of NBT
name service client, end node, and server implementations. The name
service packet implementation is still not worth a version number but
I beleive the general design concept is pretty concreate. Its pretty
simple. Basically packets are constructed by creating a NameServicePacket
object, of which there are 3 types, by passing it a byte array that will
presumably be used to construct a DatagramPacket and then call the method
that correspondes to the packet you wish to write to the byte array. The
client implemetation will be the next step I think because its so simple
and should be immediatly usefull. Then comes the end node implementation
which actually "participates" in a netbios network as a valid node. Then
comes the NBNS, session service, and datagram service. Sysnopsis of
classes follows:

mba/

	TestNameServicePackets.java

		Just runs a test program to print out pretty packet diagrams of
		a few name service packets.

mba/netbios/

	All the name service classes and some multi-threading code.

	RunTest.java

		Called by TestNameServicePackets to run test.

	NameServicePacket.java
	ClientNameServicePacket.java
	EndNodeNameServicePacket.java
	NbnsNameServicePacket.java

		Constructs/deconstructs name service packets depending on
		functionality required.

	Dump2.java

		Just dumps packet contents.

	NBTConstants.java

		Holds all constants and byte array constants for static
		regions of name service packets

	NBTNameService.java
	NBTNameServiceClient.java
	NameServiceWorker.java
	PacketHandler.java
	PacketListener.java

		Multi-threading trials

	IPAddress.java
	InetAddress.java

		Other stuff that will likely go away

	NBTName.java
	BadLabelLengthFieldException.java
	NameLengthExceededException.java
	NetBIOSException.java
	InvalidEncodedNameException.java

		Chris's name class et al.
