Ejemplo n.º 1
0
        // Encode is called by internal services if the BBMD is also an active device
        public int Encode(byte[] buffer, int offset, BacnetBvlcV6Functions function, int msg_length, BacnetAddress address)
        {
            // offset always 0, we are the first after udp

            First7BytesHeaderEncode(buffer, function, msg_length);

            // BBMD service
            if ((function == BacnetBvlcV6Functions.BVLC_ORIGINAL_BROADCAST_NPDU) && (BBMD_FD_ServiceActivated == true))
            {
                Net.IPEndPoint me = MyTransport.LocalEndPoint;
                BacnetAddress  Bacme;
                BacnetIpV6UdpProtocolTransport.Convert(me, out Bacme);
                Array.Copy(VMAC, Bacme.VMac, 3);

                Forward_NPDU(buffer, msg_length, false, me, Bacme); // send to all BBMDs and FDs

                return(7);                                          // ready to send
            }
            if (function == BacnetBvlcV6Functions.BVLC_ORIGINAL_UNICAST_NPDU)
            {
                buffer[7] = address.VMac[0];
                buffer[8] = address.VMac[1];
                buffer[9] = address.VMac[2];
                return(10); // ready to send
            }

            return(0); // ?
        }
Ejemplo n.º 2
0
        private System.Net.IPEndPoint BBMDSentAdd(Net.IPEndPoint BBMD, Net.IPAddress Mask)
        {
            byte[] bm  = Mask.GetAddressBytes();
            byte[] bip = BBMD.Address.GetAddressBytes();

            /* annotation in Steve Karg bacnet stack :
             *
             * The B/IP address to which the Forwarded-NPDU message is
             * sent is formed by inverting the broadcast distribution
             * mask in the BDT entry and logically ORing it with the
             * BBMD address of the same entry. This process
             * produces either the directed broadcast address of the remote
             * subnet or the unicast address of the BBMD on that subnet
             * depending on the contents of the broadcast distribution
             * mask.
             *
             * remark from me :
             * for instance remote BBMD 192.168.0.1 - mask 255.255.255.255
             *      messages are forward directly to 192.168.0.1
             * remote BBMD 192.168.0.1 - mask 255.255.255.0
             *      messages are forward to 192.168.0.255, ie certainly the local broadcast
             *      address, but these datagrams are generaly destroy by the final IP router
             */

            for (int i = 0; i < bm.Length; i++)
            {
                bip[i] = (byte)(bip[i] | (~bm[i]));
            }

            return(new System.Net.IPEndPoint(new System.Net.IPAddress(bip), BBMD.Port));
        }
Ejemplo n.º 3
0
        private void Open()
        {
            System.Net.Sockets.UdpClient multicastListener = null;

            if (!m_exclusive_port)
            {
                /* We need a shared multicast "listen" port. This is the 0xBAC0 port */
                /* This will enable us to have more than 1 client, on the same machine. Perhaps it's not that important though. */
                /* We (might) only receive the multicast on this. Any unicasts to this might be eaten by another local client */
                if (m_shared_conn == null)
                {
                    m_shared_conn = new Net.Sockets.UdpClient(System.Net.Sockets.AddressFamily.InterNetworkV6);
                    m_shared_conn.ExclusiveAddressUse = false;
                    m_shared_conn.Client.SetSocketOption(Net.Sockets.SocketOptionLevel.Socket, Net.Sockets.SocketOptionName.ReuseAddress, true);
                    System.Net.EndPoint ep = new System.Net.IPEndPoint(System.Net.IPAddress.IPv6Any, m_port);
                    if (!string.IsNullOrEmpty(m_local_endpoint))
                    {
                        ep = new System.Net.IPEndPoint(Net.IPAddress.Parse(m_local_endpoint), m_port);
                    }
                    m_shared_conn.Client.Bind(ep);

                    multicastListener = m_shared_conn;
                }
                /* This is our own exclusive port. We'll recieve everything sent to this. */
                /* So this is how we'll present our selves to the world */
                if (m_exclusive_conn == null)
                {
                    System.Net.EndPoint ep = new Net.IPEndPoint(System.Net.IPAddress.IPv6Any, 0);
                    if (!string.IsNullOrEmpty(m_local_endpoint))
                    {
                        ep = new Net.IPEndPoint(Net.IPAddress.Parse(m_local_endpoint), 0);
                    }
                    m_exclusive_conn = new Net.Sockets.UdpClient((Net.IPEndPoint)ep);
                }
            }
            else
            {
                System.Net.EndPoint ep = new Net.IPEndPoint(System.Net.IPAddress.IPv6Any, m_port);
                if (!string.IsNullOrEmpty(m_local_endpoint))
                {
                    ep = new Net.IPEndPoint(Net.IPAddress.Parse(m_local_endpoint), m_port);
                }
                m_exclusive_conn = new Net.Sockets.UdpClient(System.Net.Sockets.AddressFamily.InterNetworkV6);
                m_exclusive_conn.ExclusiveAddressUse = true;
                m_exclusive_conn.Client.Bind((Net.IPEndPoint)ep);

                multicastListener = m_exclusive_conn;
            }

            multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF02::BAC0]"));
            multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF04::BAC0]"));
            multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF05::BAC0]"));
            multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF08::BAC0]"));
            multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF0E::BAC0]"));

            // If this option is enabled Yabe cannot see itself !
            // multicastListener.MulticastLoopback = false;

            bvlc = new BVLCV6(this, m_VMac);
        }
Ejemplo n.º 4
0
        // Used to initiate the BBMD & FD behaviour, if BBMD is null it start the FD activity only
        public void AddBBMDPeer(Net.IPEndPoint BBMD)
        {
            BBMD_FD_ServiceActivated = true;

            if (BBMD != null)
            {
                lock (BBMDs)
                    BBMDs.Add(BBMD);
            }
        }
Ejemplo n.º 5
0
        // Used to initiate the BBMD & FD behaviour, if BBMD is null it start the FD activity only
        public void AddBBMDPeer(Net.IPEndPoint BBMD, Net.IPAddress Mask)
        {
            BBMD_FD_ServiceActivated = true;

            if (BBMD != null)
            {
                lock (BBMDs)
                    BBMDs.Add(new KeyValuePair <System.Net.IPEndPoint, System.Net.IPAddress>(BBMD, Mask));
            }
        }
Ejemplo n.º 6
0
        public BacnetAddress GetBroadcastAddress()
        {
            BacnetAddress ret;

            // could be FF08, FF05, FF04, FF02
            System.Net.IPEndPoint ep = new Net.IPEndPoint(IPAddress.Parse("[FF0E::BAC0]"), m_port);
            Convert(ep, out ret);
            ret.net = 0xFFFF;

            return(ret);
        }
Ejemplo n.º 7
0
        // A lot of problems on Mono (Raspberry) to get the correct broadcast @
        // so this method is overridable (this allows the implementation of operating system specific code)
        // Marc solution http://stackoverflow.com/questions/8119414/how-to-query-the-subnet-masks-using-mono-on-linux for instance
        //
        protected virtual BacnetAddress _GetBroadcastAddress()
        {
            // general broadcast by default if nothing better is found
            System.Net.IPEndPoint ep = new Net.IPEndPoint(System.Net.IPAddress.Parse("255.255.255.255"), m_port);

            Net.NetworkInformation.UnicastIPAddressInformation ipAddr = null;

            if (LocalEndPoint.Address.ToString() == "0.0.0.0")
            {
                ipAddr = GettAddress_DefaultInterface();
            }
            else
            {
                // restricted local broadcast (directed ... routable)
                foreach (System.Net.NetworkInformation.NetworkInterface adapter in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces())
                {
                    foreach (System.Net.NetworkInformation.UnicastIPAddressInformation ip in adapter.GetIPProperties().UnicastAddresses)
                    {
                        if (LocalEndPoint.Address.Equals(ip.Address))
                        {
                            ipAddr = ip;
                            break;
                        }
                    }
                }
            }

            if (ipAddr != null)
            {
                try
                {
                    string[]      strCurrentIP = ipAddr.Address.ToString().Split('.');
                    string[]      strIPNetMask = ipAddr.IPv4Mask.ToString().Split('.');
                    StringBuilder BroadcastStr = new StringBuilder();
                    for (int i = 0; i < 4; i++)
                    {
                        BroadcastStr.Append(((byte)(int.Parse(strCurrentIP[i]) | ~int.Parse(strIPNetMask[i]))).ToString());
                        if (i != 3)
                        {
                            BroadcastStr.Append('.');
                        }
                    }
                    ep = new Net.IPEndPoint(System.Net.IPAddress.Parse(BroadcastStr.ToString()), m_port);
                }
                catch { }  //On mono IPv4Mask feature not implemented
            }

            BacnetAddress broadcast;

            Convert(ep, out broadcast);
            broadcast.net = 0xFFFF;
            return(broadcast);
        }
Ejemplo n.º 8
0
 // Send a Frame to each registered foreign devices, except the original sender
 private void SendToFDs(byte[] buffer, int msg_length, Net.IPEndPoint EPsender = null)
 {
     lock (ForeignDevices)
     {
         // remove oldest Device entries (Time expiration > TTL + 30s delay)
         ForeignDevices.Remove(ForeignDevices.Find(item => DateTime.Now > item.Value));
         // Send to all others, except the original sender
         foreach (KeyValuePair <System.Net.IPEndPoint, DateTime> client in ForeignDevices)
         {
             if (!(client.Key.Equals(EPsender)))
             {
                 MyTransport.Send(buffer, msg_length, client.Key);
             }
         }
     }
 }
Ejemplo n.º 9
0
 // Send a Frame to each registered foreign devices, except the original sender
 private void SendToFDs(byte[] buffer, int msgLength, Net.IPEndPoint ePsender = null)
 {
     lock (_foreignDevices)
     {
         // remove oldest Device entries (Time expiration > TTL + 30s delay)
         _foreignDevices.Remove(_foreignDevices.Find(item => DateTime.Now > item.Value));
         // Send to all others, except the original sender
         foreach (var client in _foreignDevices)
         {
             if (!client.Key.Equals(ePsender))
             {
                 _myBbmdTransport.Send(buffer, msgLength, client.Key);
             }
         }
     }
 }
Ejemplo n.º 10
0
        static string GetRemoteEndpointAddressPort(Net.IPEndPoint iPEndPoint)
        {
            //We really don't want any exceptions out of TraceUtility.
            if (iPEndPoint != null)
            {
                try
                {
                    return(iPEndPoint.Address.ToString() + ":" + iPEndPoint.Port);
                }
                catch (Exception exception)
                {
                    if (Fx.IsFatal(exception))
                    {
                        throw;
                    }
                    //ignore and continue with all non-fatal exceptions.
                }
            }

            return(string.Empty);
        }
Ejemplo n.º 11
0
        // Encode is called by internal services if the BBMD is also an active device
        public int Encode(byte[] buffer, int offset, BacnetBvlcFunctions function, int msg_length)
        {
            // offset always 0, we are the first after udp

            // do the job
            First4BytesHeaderEncode(buffer, function, msg_length);

            // optional BBMD service
            if ((BBMD_FD_ServiceActivated == true) && (function == BacnetBvlcFunctions.BVLC_ORIGINAL_BROADCAST_NPDU))
            {
                Net.IPEndPoint me = MyBBMDTransport.LocalEndPoint;
                // just sometime working, enable to get the local ep, always 0.0.0.0 if the socket is open with
                // System.Net.IPAddress.Any
                // So in this case don't send a bad message
                if ((me.Address.ToString() != "0.0.0.0"))
                {
                    Forward_NPDU(buffer, msg_length, false, me);   // send to all BBMDs and FDs
                }
            }
            return(4); // ready to send
        }
Ejemplo n.º 12
0
        // Never tested
        private void Forward_NPDU(byte[] buffer, int msg_length, bool ToGlobalBroadcast, Net.IPEndPoint EPsender, BacnetAddress BacSender)
        {
            // Forms the forwarded NPDU from the original (broadcast npdu), and send it to all

            // copy, 18 bytes shifted (orignal bvlc header : 7 bytes, new one : 25 bytes)
            byte[] b = new byte[msg_length + 18];    // normaly only 'small' frames are present here, so no need to check if it's to big for Udp
            Array.Copy(buffer, 0, b, 18, msg_length);

            // 7 bytes for the BVLC Header, with the embedded 6 bytes IP:Port of the original sender
            First7BytesHeaderEncode(b, BacnetBvlcV6Functions.BVLC_FORWARDED_NPDU, msg_length + 18);
            // replace my Vmac by the orignal source vmac
            Array.Copy(BacSender.VMac, 0, b, 4, 3);
            // Add IpV6 endpoint
            Array.Copy(BacSender.adr, 0, b, 7, 18);
            // Send To BBMD
            SendToBBMDs(b, msg_length + 18);
            // Send To FD, except the sender
            SendToFDs(b, msg_length + 18, EPsender);
            // Broadcast if required
            if (ToGlobalBroadcast == true)
            {
                IPEndPoint ep;
                BacnetIpV6UdpProtocolTransport.Convert(BroadcastAdd, out ep);
                MyTransport.Send(b, msg_length + 18, ep);
            }
        }
Ejemplo n.º 13
0
        private void Forward_NPDU(byte[] buffer, int msg_length, bool ToGlobalBroadcast, Net.IPEndPoint EPsender)
        {
            // Forms the forwarded NPDU from the original one, and send it to all
            // orignal     - 4 bytes BVLC -  NPDU  - APDU
            // change to   -  10 bytes BVLC  -  NPDU  - APDU

            // copy, 6 bytes shifted
            byte[] b = new byte[msg_length + 6];    // normaly only 'small' frames are present here, so no need to check if it's to big for Udp
            Array.Copy(buffer, 0, b, 6, msg_length);

            // 10 bytes for the BVLC Header, with the embedded 6 bytes IP:Port of the original sender
            First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_FORWARDED_NPDU, msg_length + 6);
            BacnetAddress BacSender;

            BacnetIpUdpProtocolTransport.Convert(EPsender, out BacSender); // to embbed in the forward BVLC header
            for (int i = 0; i < BacSender.adr.Length; i++)
            {
                b[4 + i] = BacSender.adr[i];
            }

            // To BBMD
            SendToBBMDs(b, msg_length + 6);
            // To FD, except the sender
            SendToFDs(b, msg_length + 6, EPsender);
            // Broadcast if required
            if (ToGlobalBroadcast == true)
            {
                MyBBMDTransport.Send(b, msg_length + 6, new Net.IPEndPoint(Net.IPAddress.Parse(BroadcastAdd), MyBBMDTransport.SharedPort));
            }
        }
Ejemplo n.º 14
0
        private void OnReceiveData(IAsyncResult asyncResult)
        {
            System.Net.Sockets.UdpClient conn = (System.Net.Sockets.UdpClient)asyncResult.AsyncState;
            try
            {
                System.Net.IPEndPoint ep = new Net.IPEndPoint(System.Net.IPAddress.Any, 0);
                byte[] local_buffer;
                int    rx = 0;

                try
                {
                    local_buffer = conn.EndReceive(asyncResult, ref ep);
                    rx           = local_buffer.Length;
                }
                catch (Exception) // ICMP port unreachable
                {
                    //restart data receive
                    conn.BeginReceive(OnReceiveData, conn);
                    return;
                }

                if (rx == 0)    // Empty frame : port scanner maybe
                {
                    //restart data receive
                    conn.BeginReceive(OnReceiveData, conn);
                    return;
                }

                try
                {
                    // restart data reception before the job is finish ... could be dangerous
                    conn.BeginReceive(OnReceiveData, conn);

                    //verify message
                    BacnetAddress remote_address;
                    Convert((System.Net.IPEndPoint)ep, out remote_address);
                    BacnetBvlcFunctions function;
                    int msg_length;
                    if (rx < BVLC.BVLC_HEADER_LENGTH)
                    {
                        Trace.TraceWarning("Some garbage data got in");
                    }
                    else
                    {
                        // Basic Header lenght
                        int HEADER_LENGTH = bvlc.Decode(local_buffer, 0, out function, out msg_length, ep);

                        if (HEADER_LENGTH == -1)
                        {
                            Trace.WriteLine("Unknow BVLC Header");
                            return;
                        }

                        // response to BVLC_REGISTER_FOREIGN_DEVICE (could be BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK ... but we are not a BBMD, don't care)
                        if (function == BacnetBvlcFunctions.BVLC_RESULT)
                        {
                            Trace.WriteLine("Receive Register as Foreign Device Response");
                        }

                        // a BVLC_FORWARDED_NPDU frame by a BBMD, change the remote_address to the original one (stored in the BVLC header)
                        // we don't care about the BBMD address
                        if (function == BacnetBvlcFunctions.BVLC_FORWARDED_NPDU)
                        {
                            long ip   = ((long)local_buffer[7] << 24) + ((long)local_buffer[6] << 16) + ((long)local_buffer[5] << 8) + (long)local_buffer[4];
                            int  port = (local_buffer[8] << 8) + local_buffer[9];   // 0xbac0 maybe
                            ep = new Net.IPEndPoint(ip, port);

                            Convert((System.Net.IPEndPoint)ep, out remote_address);
                        }

                        if ((function == BacnetBvlcFunctions.BVLC_ORIGINAL_UNICAST_NPDU) || (function == BacnetBvlcFunctions.BVLC_ORIGINAL_BROADCAST_NPDU) || (function == BacnetBvlcFunctions.BVLC_FORWARDED_NPDU))
                        {
                            //send to upper layers
                            if ((MessageRecieved != null) && (rx > HEADER_LENGTH))
                            {
                                MessageRecieved(this, local_buffer, HEADER_LENGTH, rx - HEADER_LENGTH, remote_address);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError("Exception in udp recieve: " + ex.Message);
                }
                finally
                {
                    //restart data receive
                    //conn.BeginReceive(OnReceiveData, conn);
                }
            }
            catch (Exception ex)
            {
                //restart data receive
                if (conn.Client != null)
                {
                    Trace.TraceError("Exception in Ip OnRecieveData: " + ex.Message);
                    conn.BeginReceive(OnReceiveData, conn);
                }
            }
        }
Ejemplo n.º 15
0
        private void Open()
        {
            if (!m_exclusive_port)
            {
                /* We need a shared broadcast "listen" port. This is the 0xBAC0 port */
                /* This will enable us to have more than 1 client, on the same machine. Perhaps it's not that important though. */
                /* We (might) only recieve the broadcasts on this. Any unicasts to this might be eaten by another local client */
                if (m_shared_conn == null)
                {
                    m_shared_conn = new Net.Sockets.UdpClient();
                    m_shared_conn.ExclusiveAddressUse = false;
                    m_shared_conn.Client.SetSocketOption(Net.Sockets.SocketOptionLevel.Socket, Net.Sockets.SocketOptionName.ReuseAddress, true);
                    System.Net.EndPoint ep = new System.Net.IPEndPoint(System.Net.IPAddress.Any, m_port);
                    if (!string.IsNullOrEmpty(m_local_endpoint))
                    {
                        ep = new System.Net.IPEndPoint(Net.IPAddress.Parse(m_local_endpoint), m_port);
                    }
                    m_shared_conn.Client.Bind(ep);
                    m_shared_conn.DontFragment = m_dont_fragment;
                }

                /* This is our own exclusive port. We'll receive everything sent to this. */
                /* So this is how we'll present our selves to the world */
                if (m_exclusive_conn == null)
                {
                    System.Net.EndPoint ep = new Net.IPEndPoint(System.Net.IPAddress.Any, 0);
                    if (!string.IsNullOrEmpty(m_local_endpoint))
                    {
                        ep = new Net.IPEndPoint(Net.IPAddress.Parse(m_local_endpoint), 0);
                    }

                    // Opens the socket, udp will choose the Port number
                    m_exclusive_conn = new Net.Sockets.UdpClient((Net.IPEndPoint)ep);
                    // Gets the Endpoint : the assigned Udp port number in fact
                    ep = m_exclusive_conn.Client.LocalEndPoint;
                    // closes the socket
                    m_exclusive_conn.Close();
                    // Re-opens it with the freeed port number, to be sure it's a real active/server socket
                    // which cannot be disarmed for listen by .NET for incoming call after a few inactivity
                    // minutes ... yes it's like this at least on several systems
                    m_exclusive_conn = new Net.Sockets.UdpClient((Net.IPEndPoint)ep);

                    m_exclusive_conn.DontFragment    = m_dont_fragment;
                    m_exclusive_conn.EnableBroadcast = true;
                }
            }
            else
            {
                System.Net.EndPoint ep = new Net.IPEndPoint(System.Net.IPAddress.Any, m_port);
                if (!string.IsNullOrEmpty(m_local_endpoint))
                {
                    ep = new Net.IPEndPoint(Net.IPAddress.Parse(m_local_endpoint), m_port);
                }
                m_exclusive_conn = new Net.Sockets.UdpClient();
                m_exclusive_conn.ExclusiveAddressUse = true;
                m_exclusive_conn.Client.Bind((Net.IPEndPoint)ep);
                m_exclusive_conn.DontFragment = m_dont_fragment; m_exclusive_conn.EnableBroadcast = true;
            }

            bvlc = new BVLC(this);
        }