예제 #1
0
        /// <summary>
        /// Disconnect the session
        /// </summary>
        /// <param name="sessionId">The session id</param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when disconnect fails
        /// </exception>
        public void Disconnect(int sessionId)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBHANGUP;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_lsn      = (byte)sessionId;

                InvokeNetBios(ref ncb);

                //if remote machine disconnect the session first, local call disconnect will return NRC_SNUMOUT,
                //and this is not an error which we need to notify user.
                if ((ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET) &&
                    (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_SNUMOUT) &&
                    (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_SCLOSED))
                {
                    throw new InvalidOperationException("Failed in NCBHANGUP command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
예제 #2
0
        /// <summary>
        /// Cancel the previous pending listen call
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        public void CancelListen()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            lock (listeningNcbLocker)
            {
                if (listeningNcbPtr == IntPtr.Zero)
                {
                    return;
                }

                NCB ncb = new NCB();

                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBCANCEL;
                ncb.ncb_buffer   = listeningNcbPtr;
                ncb.ncb_length   = (ushort)listeningNcbSize;
                ncb.ncb_lana_num = networkAdapterId;

                InvokeNetBios(ref ncb);
            }
        }
예제 #3
0
        /// <summary>
        /// Listen to local netbios endpoint
        /// </summary>
        /// <returns>The connected session id</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when listen fails
        /// </exception>
        public byte Listen()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBLISTEN;
                ncb.ncb_lana_num = networkAdapterId;
                //* means it can accept any connection.
                ncb.ncb_callname = NetbiosUtility.ToNetbiosName("*");
                ncb.ncb_name     = NetbiosUtility.ToNetbiosName(localNetbiosName);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBLISTEN command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }

            return(ncb.ncb_lsn);
        }
예제 #4
0
        /// <summary>
        /// Unregister the bios name
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        public void UnRegisterName()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            // if the local name in .ctr is null, exception is thrown,
            // the gc will dispose the object and this method will be invoked.
            if (this.localNetbiosName == null)
            {
                return;
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBDELNAME;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_num      = ncbNum;
                ncb.ncb_name     = NetbiosUtility.ToNetbiosName(localNetbiosName);

                InvokeNetBios(ref ncb);
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
예제 #5
0
        /// <summary>
        /// Reset the adapter, it will clear all registered names, and reset the maxsession,
        /// maxName
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when reset adapter fails
        /// </exception>
        public void ResetAdapter()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBRESET;
                ncb.ncb_lana_num = networkAdapterId;
                Marshal.WriteByte(ncb.ncb_callname, 0, this.maxSessionNum);
                Marshal.WriteByte(ncb.ncb_callname, 2, this.maxNames);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBRESET command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
예제 #6
0
        /// <summary>
        /// Register bios name for further call
        /// </summary>
        /// <returns>The name index</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when register name fails
        /// </exception>
        public byte RegisterName()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBADDNAME;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_name     = NetbiosUtility.ToNetbiosName(localNetbiosName);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBADDNAME command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }

                this.ncbNum = ncb.ncb_num;
                return(ncb.ncb_num);
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
예제 #7
0
        /// <summary>
        /// Marshal NCB structure to native buffer
        /// </summary>
        /// <param name="ncb">The NCB structure</param>
        /// <param name="ncbSize">The native buffer size</param>
        /// <returns>The native buffer point</returns>
        public static IntPtr MarshalNcb(ref NCB ncb, out int ncbSize)
        {
            // size:
            if (IsWin64())
            {
                ncbSize = NetbiosUtility.Win64NcbStructSize;
            }
            else
            {
                ncbSize = NetbiosUtility.Win32NcbStructSize;
            }

            // the IntPtr used to marshal/unmarshal the NCB struct:
            IntPtr pNcb = Marshal.AllocHGlobal(ncbSize);

            // to bytes:
            byte[] ncbBytes = new byte[ncbSize];
            using (MemoryStream stream = new MemoryStream(ncbBytes, true))
            {
                stream.WriteByte((byte)ncb.ncb_command);
                stream.WriteByte((byte)ncb.ncb_retcode);
                stream.WriteByte(ncb.ncb_lsn);
                stream.WriteByte(ncb.ncb_num);

                if (ncb.ncb_padding0 != null)
                {
                    stream.Write(ncb.ncb_padding0, 0, ncb.ncb_padding0.Length);
                }
                stream.Write(BitConverter.GetBytes(ncb.ncb_buffer.ToInt64()), 0, IntPtr.Size);

                stream.Write(BitConverter.GetBytes(ncb.ncb_length), 0, 2);
                stream.Write(ncb.ncb_callname, 0, ncb.ncb_callname.Length);
                stream.Write(ncb.ncb_name, 0, ncb.ncb_name.Length);
                stream.WriteByte(ncb.ncb_rto);
                stream.WriteByte(ncb.ncb_sto);

                if (ncb.ncb_padding1 != null)
                {
                    stream.Write(ncb.ncb_padding1, 0, ncb.ncb_padding1.Length);
                }
                stream.Write(BitConverter.GetBytes(ncb.ncb_post.ToInt64()), 0, IntPtr.Size);

                stream.WriteByte(ncb.ncb_lana_num);
                stream.WriteByte(ncb.ncb_cmd_cplt);
                stream.Write(ncb.ncb_reserve, 0, ncb.ncb_reserve.Length);

                if (ncb.ncb_padding2 != null)
                {
                    stream.Write(ncb.ncb_padding2, 0, ncb.ncb_padding2.Length);
                }
                stream.Write(BitConverter.GetBytes(ncb.ncb_event.ToInt64()), 0, IntPtr.Size);

                Marshal.Copy(ncbBytes, 0, pNcb, ncbSize);
            }

            return(pNcb);
        }
예제 #8
0
        /// <summary>
        /// Initiate NCB structure
        /// </summary>
        /// <param name="ncb">The NCB structure</param>
        public static void InitNcb(ref NCB ncb)
        {
            ncb.ncb_callname = new byte[NetbiosUtility.NCBNAMSZ];
            ncb.ncb_name     = new byte[NetbiosUtility.NCBNAMSZ];

            if (IsWin64())
            {
                ncb.ncb_padding0 = new byte[NetbiosUtility.Win64NcbPaddingSize];
                ncb.ncb_padding1 = new byte[NetbiosUtility.Win64NcbPaddingSize];
                ncb.ncb_padding2 = new byte[NetbiosUtility.Win64NcbPaddingSize];
                ncb.ncb_reserve  = new byte[NetbiosUtility.NCBRSVSZ64];
            }
            else
            {
                ncb.ncb_reserve = new byte[NetbiosUtility.NCBRSVSZ32];
            }
        }
        /// <summary>
        /// Initiate NCB structure
        /// </summary>
        /// <param name="ncb">The NCB structure</param>
        public static void InitNcb(ref NCB ncb)
        {
            ncb.ncb_callname = new byte[NetbiosUtility.NCBNAMSZ];
            ncb.ncb_name = new byte[NetbiosUtility.NCBNAMSZ];

            if (IsWin64())
            {
                ncb.ncb_padding0 = new byte[NetbiosUtility.Win64NcbPaddingSize];
                ncb.ncb_padding1 = new byte[NetbiosUtility.Win64NcbPaddingSize];
                ncb.ncb_padding2 = new byte[NetbiosUtility.Win64NcbPaddingSize];
                ncb.ncb_reserve = new byte[NetbiosUtility.NCBRSVSZ64];
            }
            else
            {
                ncb.ncb_reserve = new byte[NetbiosUtility.NCBRSVSZ32];
            }
        }
        /// <summary>
        /// Free native resource the ncb used
        /// </summary>
        /// <param name="ncb">The network control block</param>
        public static void FreeNcbNativeFields(ref NCB ncb)
        {
            if (ncb.ncb_buffer != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ncb.ncb_buffer);
                ncb.ncb_buffer = IntPtr.Zero;
            }

            if (ncb.ncb_event != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ncb.ncb_event);
                ncb.ncb_event = IntPtr.Zero;
            }

            if (ncb.ncb_post != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ncb.ncb_post);
                ncb.ncb_post = IntPtr.Zero;
            }
        }
예제 #11
0
        /// <summary>
        /// Free native resource the ncb used
        /// </summary>
        /// <param name="ncb">The network control block</param>
        public static void FreeNcbNativeFields(ref NCB ncb)
        {
            if (ncb.ncb_buffer != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ncb.ncb_buffer);
                ncb.ncb_buffer = IntPtr.Zero;
            }

            if (ncb.ncb_event != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ncb.ncb_event);
                ncb.ncb_event = IntPtr.Zero;
            }

            if (ncb.ncb_post != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(ncb.ncb_post);
                ncb.ncb_post = IntPtr.Zero;
            }
        }
예제 #12
0
        /// <summary>
        /// Receive data
        /// </summary>
        /// <param name="sessionId">Specified the session identify</param>
        /// <returns>The received data</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when receive encounters error.
        /// </exception>
        public byte[] Receive(int sessionId)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBRECV;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_lsn      = (byte)sessionId;
                ncb.ncb_buffer   = Marshal.AllocHGlobal(maxBufferSize);
                ncb.ncb_length   = maxBufferSize;

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode == (byte)NcbReturnCode.NRC_SCLOSED)
                {
                    return(null);
                }

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBRECV command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }

                byte[] receivedData = new byte[ncb.ncb_length];
                Marshal.Copy(ncb.ncb_buffer, receivedData, 0, receivedData.Length);

                return(receivedData);
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
예제 #13
0
        /// <summary>
        /// Get the adapter id
        /// </summary>
        /// <returns>The adapter id</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when Get adapterId fails
        /// </exception>
        public byte GetAdapterId()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBENUM;
                ncb.ncb_buffer  = Marshal.AllocHGlobal(maxBufferSize);
                ncb.ncb_length  = maxBufferSize;

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBENUM command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }

                LANA_ENUM lenum = new LANA_ENUM();
                lenum.length  = Marshal.ReadByte(ncb.ncb_buffer, 0);
                lenum.lanaNum = new byte[lenum.length];

                for (int i = 0; i < lenum.length; i++)
                {
                    lenum.lanaNum[i] = Marshal.ReadByte(ncb.ncb_buffer, i + 1);
                }

                return(lenum.lanaNum[adapterIndex]);
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
예제 #14
0
        /// <summary>
        /// Connect to remote machine
        /// </summary>
        /// <param name="remoteName">The remote machine bios name</param>
        /// <returns>The session id</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when connect fails.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when remoteName is null.
        /// </exception>
        public int Connect(string remoteName)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            if (remoteName == null)
            {
                throw new ArgumentNullException("remoteName");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command  = (byte)NcbCommand.NCBCALL;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_name     = NetbiosUtility.ToNetbiosName(localNetbiosName);
                ncb.ncb_callname = NetbiosUtility.ToNetbiosName(remoteName);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBCALL command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }

            return(ncb.ncb_lsn);
        }
예제 #15
0
        /// <summary>
        /// Send data
        /// </summary>
        /// <param name="sessionId">The session id</param>
        /// <param name="buffer">The data buffer</param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// throw when the buffer is larger than the max buffer size
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when call native netbios api fails
        /// </exception>
        public void Send(int sessionId, byte[] buffer)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBSEND;
                ncb.ncb_buffer  = Marshal.AllocHGlobal(buffer.Length);
                Marshal.Copy(buffer, 0, ncb.ncb_buffer, buffer.Length);
                ncb.ncb_length   = (ushort)buffer.Length;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_lsn      = (byte)sessionId;

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBSEND command, error is "
                                                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
예제 #16
0
        /// <summary>
        /// Call native Netbios interface
        /// </summary>
        /// <param name="ncb">The NCB structure</param>
        private void InvokeNetBios(ref NCB ncb)
        {
            IntPtr ncbPtr  = IntPtr.Zero;
            int    ncbSize = 0;

            try
            {
                lock (listeningNcbLocker)
                {
                    ncbPtr = NetbiosUtility.MarshalNcb(ref ncb, out ncbSize);

                    if (ncb.ncb_command == (byte)NcbCommand.NCBLISTEN)
                    {
                        listeningNcbPtr  = ncbPtr;
                        listeningNcbSize = ncbSize;
                    }
                }

                NetbiosNativeMethods.Netbios(ncbPtr);

                ncb = NetbiosUtility.UnMarshalNcb(ncbPtr, ncbSize);
            }
            finally
            {
                lock (listeningNcbLocker)
                {
                    Marshal.FreeHGlobal(ncbPtr);

                    if (ncb.ncb_command == (byte)NcbCommand.NCBLISTEN)
                    {
                        listeningNcbPtr  = IntPtr.Zero;
                        listeningNcbSize = 0;
                    }
                }
            }
        }
예제 #17
0
        /// <summary>
        /// Un marshal NCB structure from a native buffer
        /// </summary>
        /// <param name="ncbPtr">The native buffer point</param>
        /// <param name="ncbSize">The native buffer size</param>
        /// <returns>The un-marshaled NCB structure</returns>
        /// <exception cref="System.InvalidOperationException">
        /// Throw when there is no enough data can be unmarshaled.
        /// </exception>
        public static NCB UnMarshalNcb(IntPtr ncbPtr, int ncbSize)
        {
            NCB ncb = new NCB();

            NetbiosUtility.InitNcb(ref ncb);
            byte[] ncbBytes = new byte[ncbSize];

            // to struct:
            Marshal.Copy(ncbPtr, ncbBytes, 0, ncbBytes.Length);
            using (MemoryStream stream = new MemoryStream(ncbBytes, false))
            {
                int readedBufferCount = 0;

                ncb.ncb_command = (byte)stream.ReadByte();
                ncb.ncb_retcode = (byte)stream.ReadByte();
                ncb.ncb_lsn     = (byte)stream.ReadByte();
                ncb.ncb_num     = (byte)stream.ReadByte();

                if (ncb.ncb_padding0 != null)
                {
                    stream.Read(ncb.ncb_padding0, 0, ncb.ncb_padding0.Length);
                }

                byte[] ncbBuffer = new byte[IntPtr.Size];
                readedBufferCount = stream.Read(ncbBuffer, 0, ncbBuffer.Length);

                if (readedBufferCount != ncbBuffer.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                if (!IsWin64())
                {
                    ncb.ncb_buffer = new IntPtr(BitConverter.ToInt32(ncbBuffer, 0));
                }
                else
                {
                    ncb.ncb_buffer = new IntPtr(BitConverter.ToInt64(ncbBuffer, 0));
                }

                byte[] ncbLength = new byte[sizeof(ushort)];

                readedBufferCount = stream.Read(ncbLength, 0, ncbLength.Length);
                if (readedBufferCount != ncbLength.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                ncb.ncb_length = (ushort)BitConverter.ToInt16(ncbLength, 0);

                readedBufferCount = stream.Read(ncb.ncb_callname, 0, ncb.ncb_callname.Length);

                if (readedBufferCount != ncb.ncb_callname.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                readedBufferCount = stream.Read(ncb.ncb_name, 0, ncb.ncb_name.Length);

                if (readedBufferCount != ncb.ncb_name.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                ncb.ncb_rto = (byte)stream.ReadByte();
                ncb.ncb_sto = (byte)stream.ReadByte();

                if (ncb.ncb_padding1 != null)
                {
                    stream.Read(ncb.ncb_padding1, 0, ncb.ncb_padding1.Length);
                }

                byte[] ncbPost = new byte[IntPtr.Size];
                stream.Read(ncbPost, 0, ncbPost.Length);

                if (!IsWin64())
                {
                    ncb.ncb_post = new IntPtr(BitConverter.ToInt32(ncbPost, 0));
                }
                else
                {
                    ncb.ncb_post = new IntPtr(BitConverter.ToInt64(ncbPost, 0));
                }

                ncb.ncb_lana_num = (byte)stream.ReadByte();
                ncb.ncb_cmd_cplt = (byte)stream.ReadByte();
                stream.Read(ncb.ncb_reserve, 0, ncb.ncb_reserve.Length);

                if (ncb.ncb_padding2 != null)
                {
                    stream.Read(ncb.ncb_padding2, 0, ncb.ncb_padding2.Length);
                }

                byte[] ncbEvent = new byte[IntPtr.Size];
                readedBufferCount = stream.Read(ncbEvent, 0, ncbEvent.Length);

                if (readedBufferCount != ncbEvent.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                if (!IsWin64())
                {
                    ncb.ncb_event = new IntPtr(BitConverter.ToInt32(ncbEvent, 0));
                }
                else
                {
                    ncb.ncb_event = new IntPtr(BitConverter.ToInt64(ncbEvent, 0));
                }
            }

            return(ncb);
        }
        /// <summary>
        /// Cancel the previous pending listen call
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        public void CancelListen()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            lock (listeningNcbLocker)
            {
                if (listeningNcbPtr == IntPtr.Zero)
                {
                    return;
                }

                NCB ncb = new NCB();

                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBCANCEL;
                ncb.ncb_buffer = listeningNcbPtr;
                ncb.ncb_length = (ushort)listeningNcbSize;
                ncb.ncb_lana_num = networkAdapterId;

                InvokeNetBios(ref ncb);
            }
        }
        /// <summary>
        /// Un marshal NCB structure from a native buffer
        /// </summary>
        /// <param name="ncbPtr">The native buffer point</param>
        /// <param name="ncbSize">The native buffer size</param>
        /// <returns>The un-marshaled NCB structure</returns>
        /// <exception cref="System.InvalidOperationException">
        /// Throw when there is no enough data can be unmarshaled.
        /// </exception>
        public static NCB UnMarshalNcb(IntPtr ncbPtr, int ncbSize)
        {
            NCB ncb = new NCB();
            NetbiosUtility.InitNcb(ref ncb);
            byte[] ncbBytes = new byte[ncbSize];

            // to struct:
            Marshal.Copy(ncbPtr, ncbBytes, 0, ncbBytes.Length);
            using (MemoryStream stream = new MemoryStream(ncbBytes, false))
            {
                int readedBufferCount = 0;

                ncb.ncb_command = (byte)stream.ReadByte();
                ncb.ncb_retcode = (byte)stream.ReadByte();
                ncb.ncb_lsn = (byte)stream.ReadByte();
                ncb.ncb_num = (byte)stream.ReadByte();

                if (ncb.ncb_padding0 != null)
                {
                    stream.Read(ncb.ncb_padding0, 0, ncb.ncb_padding0.Length);
                }

                byte[] ncbBuffer = new byte[IntPtr.Size];
                readedBufferCount = stream.Read(ncbBuffer, 0, ncbBuffer.Length);

                if (readedBufferCount != ncbBuffer.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                if (!IsWin64())
                {
                    ncb.ncb_buffer = new IntPtr(BitConverter.ToInt32(ncbBuffer, 0));
                }
                else
                {
                    ncb.ncb_buffer = new IntPtr(BitConverter.ToInt64(ncbBuffer, 0));
                }

                byte[] ncbLength = new byte[sizeof(ushort)];

                readedBufferCount = stream.Read(ncbLength, 0, ncbLength.Length);
                if (readedBufferCount != ncbLength.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                ncb.ncb_length = (ushort)BitConverter.ToInt16(ncbLength, 0);

                readedBufferCount = stream.Read(ncb.ncb_callname, 0, ncb.ncb_callname.Length);

                if (readedBufferCount != ncb.ncb_callname.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                readedBufferCount = stream.Read(ncb.ncb_name, 0, ncb.ncb_name.Length);

                if (readedBufferCount != ncb.ncb_name.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                ncb.ncb_rto = (byte)stream.ReadByte();
                ncb.ncb_sto = (byte)stream.ReadByte();

                if (ncb.ncb_padding1 != null)
                {
                    stream.Read(ncb.ncb_padding1, 0, ncb.ncb_padding1.Length);
                }

                byte[] ncbPost = new byte[IntPtr.Size];
                stream.Read(ncbPost, 0, ncbPost.Length);

                if (!IsWin64())
                {
                    ncb.ncb_post = new IntPtr(BitConverter.ToInt32(ncbPost, 0));
                }
                else
                {
                    ncb.ncb_post = new IntPtr(BitConverter.ToInt64(ncbPost, 0));
                }

                ncb.ncb_lana_num = (byte)stream.ReadByte();
                ncb.ncb_cmd_cplt = (byte)stream.ReadByte();
                stream.Read(ncb.ncb_reserve, 0, ncb.ncb_reserve.Length);

                if (ncb.ncb_padding2 != null)
                {
                    stream.Read(ncb.ncb_padding2, 0, ncb.ncb_padding2.Length);
                }

                byte[] ncbEvent = new byte[IntPtr.Size];
                readedBufferCount = stream.Read(ncbEvent, 0, ncbEvent.Length);

                if (readedBufferCount != ncbEvent.Length)
                {
                    throw new InvalidOperationException("No enough data can be read");
                }

                if (!IsWin64())
                {
                    ncb.ncb_event = new IntPtr(BitConverter.ToInt32(ncbEvent, 0));
                }
                else
                {
                    ncb.ncb_event = new IntPtr(BitConverter.ToInt64(ncbEvent, 0));
                }
            }

            return ncb;
        }
        /// <summary>
        /// Marshal NCB structure to native buffer
        /// </summary>
        /// <param name="ncb">The NCB structure</param>
        /// <param name="ncbSize">The native buffer size</param>
        /// <returns>The native buffer point</returns>
        public static IntPtr MarshalNcb(ref NCB ncb, out int ncbSize)
        {
            // size:
            if (IsWin64())
            {
                ncbSize = NetbiosUtility.Win64NcbStructSize;
            }
            else
            {
                ncbSize = NetbiosUtility.Win32NcbStructSize;
            }

            // the IntPtr used to marshal/unmarshal the NCB struct:
            IntPtr pNcb = Marshal.AllocHGlobal(ncbSize);

            // to bytes:
            byte[] ncbBytes = new byte[ncbSize];
            using (MemoryStream stream = new MemoryStream(ncbBytes, true))
            {
                stream.WriteByte((byte)ncb.ncb_command);
                stream.WriteByte((byte)ncb.ncb_retcode);
                stream.WriteByte(ncb.ncb_lsn);
                stream.WriteByte(ncb.ncb_num);

                if (ncb.ncb_padding0 != null)
                {
                    stream.Write(ncb.ncb_padding0, 0, ncb.ncb_padding0.Length);
                }
                stream.Write(BitConverter.GetBytes(ncb.ncb_buffer.ToInt64()), 0, IntPtr.Size);

                stream.Write(BitConverter.GetBytes(ncb.ncb_length), 0, 2);
                stream.Write(ncb.ncb_callname, 0, ncb.ncb_callname.Length);
                stream.Write(ncb.ncb_name, 0, ncb.ncb_name.Length);
                stream.WriteByte(ncb.ncb_rto);
                stream.WriteByte(ncb.ncb_sto);

                if (ncb.ncb_padding1 != null)
                {
                    stream.Write(ncb.ncb_padding1, 0, ncb.ncb_padding1.Length);
                }
                stream.Write(BitConverter.GetBytes(ncb.ncb_post.ToInt64()), 0, IntPtr.Size);

                stream.WriteByte(ncb.ncb_lana_num);
                stream.WriteByte(ncb.ncb_cmd_cplt);
                stream.Write(ncb.ncb_reserve, 0, ncb.ncb_reserve.Length);

                if (ncb.ncb_padding2 != null)
                {
                    stream.Write(ncb.ncb_padding2, 0, ncb.ncb_padding2.Length);
                }
                stream.Write(BitConverter.GetBytes(ncb.ncb_event.ToInt64()), 0, IntPtr.Size);

                Marshal.Copy(ncbBytes, 0, pNcb, ncbSize);
            }

            return pNcb;
        }
        /// <summary>
        /// Connect to remote machine
        /// </summary>
        /// <param name="remoteName">The remote machine bios name</param>
        /// <returns>The session id</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when connect fails.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when remoteName is null.
        /// </exception>
        public int Connect(string remoteName)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            if (remoteName == null)
            {
                throw new ArgumentNullException("remoteName");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBCALL;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_name = NetbiosUtility.ToNetbiosName(localNetbiosName);
                ncb.ncb_callname = NetbiosUtility.ToNetbiosName(remoteName);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBCALL command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }

            return ncb.ncb_lsn;
        }
        /// <summary>
        /// Disconnect the session
        /// </summary>
        /// <param name="sessionId">The session id</param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when disconnect fails
        /// </exception>
        public void Disconnect(int sessionId)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBHANGUP;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_lsn = (byte)sessionId;

                InvokeNetBios(ref ncb);

                //if remote machine disconnect the session first, local call disconnect will return NRC_SNUMOUT,
                //and this is not an error which we need to notify user.
                if ((ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                    && (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_SNUMOUT)
                    && (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_SCLOSED))
                {
                    throw new InvalidOperationException("Failed in NCBHANGUP command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
        /// <summary>
        /// Get the adapter id
        /// </summary>
        /// <returns>The adapter id</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when Get adapterId fails
        /// </exception>
        public byte GetAdapterId()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBENUM;
                ncb.ncb_buffer = Marshal.AllocHGlobal(maxBufferSize);
                ncb.ncb_length = maxBufferSize;

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBENUM command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }

                LANA_ENUM lenum = new LANA_ENUM();
                lenum.length = Marshal.ReadByte(ncb.ncb_buffer, 0);
                lenum.lanaNum = new byte[lenum.length];

                for (int i = 0; i < lenum.length; i++)
                {
                    lenum.lanaNum[i] = Marshal.ReadByte(ncb.ncb_buffer, i + 1);
                }

                return lenum.lanaNum[adapterIndex];
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
        /// <summary>
        /// Listen to local netbios endpoint
        /// </summary>
        /// <returns>The connected session id</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when listen fails
        /// </exception>
        public byte Listen()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBLISTEN;
                ncb.ncb_lana_num = networkAdapterId;
                //* means it can accept any connection.
                ncb.ncb_callname = NetbiosUtility.ToNetbiosName("*");
                ncb.ncb_name = NetbiosUtility.ToNetbiosName(localNetbiosName);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBLISTEN command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }

            return ncb.ncb_lsn;
        }
        /// <summary>
        /// Receive data
        /// </summary>
        /// <param name="sessionId">Specified the session identify</param>
        /// <returns>The received data</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when receive encounters error.
        /// </exception>
        public byte[] Receive(int sessionId)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBRECV;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_lsn = (byte)sessionId;
                ncb.ncb_buffer = Marshal.AllocHGlobal(maxBufferSize);
                ncb.ncb_length = maxBufferSize;

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode == (byte)NcbReturnCode.NRC_SCLOSED)
                {
                    return null;
                }

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBRECV command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }

                byte[] receivedData = new byte[ncb.ncb_length];
                Marshal.Copy(ncb.ncb_buffer, receivedData, 0, receivedData.Length);

                return receivedData;
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
        /// <summary>
        /// Register bios name for further call
        /// </summary>
        /// <returns>The name index</returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when register name fails
        /// </exception>
        public byte RegisterName()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBADDNAME;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_name = NetbiosUtility.ToNetbiosName(localNetbiosName);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBADDNAME command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }

                this.ncbNum = ncb.ncb_num;
                return ncb.ncb_num;
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
        /// <summary>
        /// Reset the adapter, it will clear all registered names, and reset the maxsession,
        /// maxName
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when reset adapter fails
        /// </exception>
        public void ResetAdapter()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBRESET;
                ncb.ncb_lana_num = networkAdapterId;
                Marshal.WriteByte(ncb.ncb_callname, 0, this.maxSessionNum);
                Marshal.WriteByte(ncb.ncb_callname, 2, this.maxNames);

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBRESET command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
        /// <summary>
        /// Send data
        /// </summary>
        /// <param name="sessionId">The session id</param>
        /// <param name="buffer">The data buffer</param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// throw when the buffer is larger than the max buffer size
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// throw when call native netbios api fails
        /// </exception>
        public void Send(int sessionId, byte[] buffer)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBSEND;
                ncb.ncb_buffer = Marshal.AllocHGlobal(buffer.Length);
                Marshal.Copy(buffer, 0, ncb.ncb_buffer, buffer.Length);
                ncb.ncb_length = (ushort)buffer.Length;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_lsn = (byte)sessionId;

                InvokeNetBios(ref ncb);

                if (ncb.ncb_retcode != (byte)NcbReturnCode.NRC_GOODRET)
                {
                    throw new InvalidOperationException("Failed in NCBSEND command, error is "
                        + ((NcbReturnCode)ncb.ncb_retcode).ToString());
                }
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
        /// <summary>
        /// Unregister the bios name
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        public void UnRegisterName()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosTransport");
            }

            // if the local name in .ctr is null, exception is thrown,
            // the gc will dispose the object and this method will be invoked.
            if (this.localNetbiosName == null)
            {
                return;
            }

            NCB ncb = new NCB();

            try
            {
                NetbiosUtility.InitNcb(ref ncb);
                ncb.ncb_command = (byte)NcbCommand.NCBDELNAME;
                ncb.ncb_lana_num = networkAdapterId;
                ncb.ncb_num = ncbNum;
                ncb.ncb_name = NetbiosUtility.ToNetbiosName(localNetbiosName);

                InvokeNetBios(ref ncb);
            }
            finally
            {
                NetbiosUtility.FreeNcbNativeFields(ref ncb);
            }
        }
        /// <summary>
        /// Call native Netbios interface
        /// </summary>
        /// <param name="ncb">The NCB structure</param>
        private void InvokeNetBios(ref NCB ncb)
        {
            IntPtr ncbPtr = IntPtr.Zero;
            int ncbSize = 0;

            try
            {
                lock (listeningNcbLocker)
                {
                    ncbPtr = NetbiosUtility.MarshalNcb(ref ncb, out ncbSize);

                    if (ncb.ncb_command == (byte)NcbCommand.NCBLISTEN)
                    {
                        listeningNcbPtr = ncbPtr;
                        listeningNcbSize = ncbSize;
                    }
                }

                NetbiosNativeMethods.Netbios(ncbPtr);

                ncb = NetbiosUtility.UnMarshalNcb(ncbPtr, ncbSize);
            }
            finally
            {
                lock (listeningNcbLocker)
                {
                    Marshal.FreeHGlobal(ncbPtr);

                    if (ncb.ncb_command == (byte)NcbCommand.NCBLISTEN)
                    {
                        listeningNcbPtr = IntPtr.Zero;
                        listeningNcbSize = 0;
                    }
                }
            }
        }