public void TestTrapV3AuthBytes()
        {
            byte[]       bytes                = File.ReadAllBytes(Path.Combine("Resources", "v3authNoPriv_BER_Issue"));
            UserRegistry registry             = new UserRegistry();
            SHA1AuthenticationProvider authen = new SHA1AuthenticationProvider(new OctetString("testpass"));

            registry.Add(new OctetString("test"), new DefaultPrivacyProvider(authen));
            IList <ISnmpMessage> messages = MessageFactory.ParseMessages(bytes, registry);

            Assert.Equal(1, messages.Count);
            ISnmpMessage message = messages[0];

            Assert.Equal("80001299030005B706CF69", message.Parameters.EngineId.ToHexString());
            Assert.Equal(41, message.Parameters.EngineBoots.ToInt32());
            Assert.Equal(877, message.Parameters.EngineTime.ToInt32());
            Assert.Equal("test", message.Parameters.UserName.ToString());
            Assert.Equal("C107F9DAA3FC552960E38936", message.Parameters.AuthenticationParameters.ToHexString());
            Assert.Equal("", message.Parameters.PrivacyParameters.ToHexString());
            Assert.Equal("80001299030005B706CF69", message.Scope.ContextEngineId.ToHexString()); // SNMP#NET returns string.Empty here.
            Assert.Equal("", message.Scope.ContextName.ToHexString());
            Assert.Equal(681323585, message.MessageId());
            Assert.Equal(681323584, message.RequestId());

            Assert.Equal(bytes, message.ToBytes());
        }
        public void TestTrapV3AuthPriv()
        {
            if (!DESPrivacyProvider.IsSupported)
            {
                return;
            }

            // The message body generated by snmp#net is problematic.
            byte[]       bytes    = File.ReadAllBytes(Path.Combine("Resources", "trapv3authpriv"));
            UserRegistry registry = new UserRegistry();

            registry.Add(new OctetString("lextm"), new DESPrivacyProvider(new OctetString("privacyphrase"), new MD5AuthenticationProvider(new OctetString("authentication"))));
            IList <ISnmpMessage> messages = MessageFactory.ParseMessages(bytes, registry);

            Assert.Equal(1, messages.Count);
            ISnmpMessage message = messages[0];

            Assert.Equal("80001F8880E9630000D61FF449", message.Parameters.EngineId.ToHexString());
            Assert.Equal(0, message.Parameters.EngineBoots.ToInt32());
            Assert.Equal(0, message.Parameters.EngineTime.ToInt32());
            Assert.Equal("lextm", message.Parameters.UserName.ToString());
            Assert.Equal("89D351891A55829243617F2C", message.Parameters.AuthenticationParameters.ToHexString());
            Assert.Equal("0000000069D39B2A", message.Parameters.PrivacyParameters.ToHexString());
            Assert.Equal("", message.Scope.ContextEngineId.ToHexString()); // SNMP#NET returns string.Empty here.
            Assert.Equal("", message.Scope.ContextName.ToHexString());
            Assert.Equal(0, message.Scope.Pdu.Variables.Count);
            Assert.Equal(1004947569, message.MessageId());
            Assert.Equal(234419641, message.RequestId());
        }
        public static ISnmpMessage EndGetResponse(this ISnmpMessage request, IAsyncResult asyncResult)
        {
            if (asyncResult == null)
            {
                throw new ArgumentNullException(nameof(asyncResult));
            }

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var ar    = (SnmpMessageAsyncResult)asyncResult;
            var s     = ar.WorkSocket;
            var count = s.EndReceive(ar.Inner);

            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
            var response     = MessageFactory.ParseMessages(ar.GetBuffer(), 0, count, ar.Users)[0];
            var responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                var requestId  = request.MessageId();
                var responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), ar.Receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), ar.Receiver.Address);
        }
Esempio n. 4
0
        /// <summary>
        /// Sends an  <see cref="ISnmpMessage"/> and handles the response from agent.
        /// </summary>
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
        /// <param name="connectionTimeout">The time-out value, in milliseconds for how long to wait for a connection</param>
        /// <param name="responseTimeout">The time-out value, in milliseconds for how long to wait for a response. The default value is 0, which indicates an infinite time-out period. Specifying -1 also indicates an infinite time-out period.</param>
        /// <param name="receiver">Agent.</param>
        /// <param name="client">The DTLS client</param>
        /// <param name="registry">The user registry.</param>
        /// <returns></returns>
        public static async Task <ISnmpMessage> GetSecureResponseAsync(this ISnmpMessage request, TimeSpan connectionTimeout, TimeSpan responseTimeout, IPEndPoint receiver, Client client, UserRegistry registry)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (receiver == null)
            {
                throw new ArgumentNullException(nameof(receiver));
            }

            if (client is null)
            {
                throw new ArgumentNullException(nameof(client));
            }

            if (registry == null)
            {
                throw new ArgumentNullException(nameof(registry));
            }

            var requestCode = request.TypeCode();

            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
            }

            var bytes = request.ToBytes();
            await client.ConnectToServerAsync(receiver, responseTimeout, connectionTimeout).ConfigureAwait(false);

            var reply = await client.SendAndGetResponseAsync(bytes, responseTimeout).ConfigureAwait(false);

            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
            var response     = MessageFactory.ParseMessages(reply, 0, reply.Length, registry)[0];
            var responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                var requestId  = request.MessageId();
                var responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address);
        }
        public void TestToBytes3()
        {
            if (!DESPrivacyProvider.IsSupported)
            {
                return;
            }

            var privacy = new DESPrivacyProvider(new OctetString("privacyphrase"), new MD5AuthenticationProvider(new OctetString("authentication")));
            var trap    = new TrapV2Message(
                VersionCode.V3,
                new Header(
                    new Integer32(1004947569),
                    new Integer32(0x10000),
                    privacy.ToSecurityLevel()),
                new SecurityParameters(
                    new OctetString(ByteTool.Convert("80001F8880E9630000D61FF449")),
                    Integer32.Zero,
                    Integer32.Zero,
                    new OctetString("lextm"),
                    new OctetString(ByteTool.Convert("61A9A486AF4A861BD5C0BB1F")),
                    new OctetString(ByteTool.Convert("0000000069D39B2A"))),
                new Scope(OctetString.Empty, OctetString.Empty,
                          new TrapV2Pdu(
                              234419641,
                              new ObjectIdentifier("1.3.6"),
                              0,
                              new List <Variable>())),
                privacy,
                null);

            byte[]       bytes    = trap.ToBytes();
            UserRegistry registry = new UserRegistry();

            registry.Add(new OctetString("lextm"), privacy);
            IList <ISnmpMessage> messages = MessageFactory.ParseMessages(bytes, registry);

            Assert.Equal(1, messages.Count);
            ISnmpMessage message = messages[0];

            Assert.Equal("80001F8880E9630000D61FF449", message.Parameters.EngineId.ToHexString());
            Assert.Equal(0, message.Parameters.EngineBoots.ToInt32());
            Assert.Equal(0, message.Parameters.EngineTime.ToInt32());
            Assert.Equal("lextm", message.Parameters.UserName.ToString());
            Assert.Equal("61A9A486AF4A861BD5C0BB1F", message.Parameters.AuthenticationParameters.ToHexString());
            Assert.Equal("0000000069D39B2A", message.Parameters.PrivacyParameters.ToHexString());
            Assert.Equal("", message.Scope.ContextEngineId.ToHexString()); // SNMP#NET returns string.Empty here.
            Assert.Equal("", message.Scope.ContextName.ToHexString());
            Assert.Equal(0, message.Scope.Pdu.Variables.Count);
            Assert.Equal(1004947569, message.MessageId());
            Assert.Equal(234419641, message.RequestId());
        }
        public void TestTrapV3Auth()
        {
            byte[]       bytes    = File.ReadAllBytes(Path.Combine("Resources", "trapv3auth"));
            UserRegistry registry = new UserRegistry();

            registry.Add(new OctetString("lextm"), new DefaultPrivacyProvider(new MD5AuthenticationProvider(new OctetString("authentication"))));
            IList <ISnmpMessage> messages = MessageFactory.ParseMessages(bytes, registry);

            Assert.Equal(1, messages.Count);
            ISnmpMessage message = messages[0];

            Assert.Equal("80001F8880E9630000D61FF449", message.Parameters.EngineId.ToHexString());
            Assert.Equal(0, message.Parameters.EngineBoots.ToInt32());
            Assert.Equal(0, message.Parameters.EngineTime.ToInt32());
            Assert.Equal("lextm", message.Parameters.UserName.ToString());
            Assert.Equal("84433969457707152C289A3E", message.Parameters.AuthenticationParameters.ToHexString());
            Assert.Equal("", message.Parameters.PrivacyParameters.ToHexString());
            Assert.Equal("", message.Scope.ContextEngineId.ToHexString()); // SNMP#NET returns string.Empty here.
            Assert.Equal("", message.Scope.ContextName.ToHexString());
            Assert.Equal(318463383, message.MessageId());
            Assert.Equal(1276263065, message.RequestId());
        }
        public void TestTrapV3()
        {
            byte[]       bytes    = File.ReadAllBytes(Path.Combine("Resources", "trapv3"));
            UserRegistry registry = new UserRegistry();

            registry.Add(new OctetString("lextm"), DefaultPrivacyProvider.DefaultPair);
            IList <ISnmpMessage> messages = MessageFactory.ParseMessages(bytes, registry);

            Assert.Equal(1, messages.Count);
            ISnmpMessage message = messages[0];

            Assert.Equal("80001F8880E9630000D61FF449", message.Parameters.EngineId.ToHexString());
            Assert.Equal(0, message.Parameters.EngineBoots.ToInt32());
            Assert.Equal(0, message.Parameters.EngineTime.ToInt32());
            Assert.Equal("lextm", message.Parameters.UserName.ToString());
            Assert.Equal("", message.Parameters.AuthenticationParameters.ToHexString());
            Assert.Equal("", message.Parameters.PrivacyParameters.ToHexString());
            Assert.Equal("", message.Scope.ContextEngineId.ToHexString()); // SNMP#NET returns string.Empty here.
            Assert.Equal("", message.Scope.ContextName.ToHexString());
            Assert.Equal(528732060, message.MessageId());
            Assert.Equal(1905687779, message.RequestId());
            Assert.Equal("1.3.6", ((TrapV2Message)message).Enterprise.ToString());
        }
Esempio n. 8
0
        internal static async Task <ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint remoteEndPoint, CancellationToken cancellationToken)
        {
            try
            {
                using var socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

                await socket.ConnectAsync(remoteEndPoint, cancellationToken).ConfigureAwait(false);

                var sendingBytes = request.ToBytes();
                await socket.SendAsync(sendingBytes, SocketFlags.None, cancellationToken).ConfigureAwait(false);

                var recvd      = new byte[100000];
                var recvdCount = await socket.ReceiveAsync(recvd, SocketFlags.None, cancellationToken).ConfigureAwait(false);

                var registry = new UserRegistry();
                var response = MessageFactory.ParseMessages(recvd.Take(recvdCount).ToArray(), 0, recvdCount, registry)[0];

                var responseCode = response.TypeCode();
                if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
                {
                    var requestId  = request.MessageId();
                    var responseId = response.MessageId();
                    if (responseId != requestId)
                    {
                        throw OperationException.Create($"wrong response sequence: expected {requestId}, received {responseId}", remoteEndPoint.Address);
                    }

                    return(response);
                }

                throw OperationException.Create($"wrong response type: {responseCode}", remoteEndPoint.Address);
            }
            catch (TaskCanceledException)
            {
                throw new OperationCanceledException(cancellationToken);
            }
        }
        /// <summary>
        /// Sends an <see cref="ISnmpMessage"/> and handles the response from agent.
        /// </summary>
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
        /// <param name="receiver">Agent.</param>
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
        /// <param name="registry">The user registry.</param>
        /// <returns></returns>
        public static async Task <ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint receiver, UserRegistry registry, Socket udpSocket)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (udpSocket == null)
            {
                throw new ArgumentNullException(nameof(udpSocket));
            }

            if (receiver == null)
            {
                throw new ArgumentNullException(nameof(receiver));
            }

            if (registry == null)
            {
                throw new ArgumentNullException(nameof(registry));
            }

            var requestCode = request.TypeCode();

            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
            }

            var bytes   = request.ToBytes();
            var bufSize = udpSocket.ReceiveBufferSize = Messenger.MaxMessageSize;

            // Whatever you change, try to keep the Send and the Receive close to each other.
            var info = SocketExtension.EventArgsFactory.Create();

            info.RemoteEndPoint = receiver;
            info.SetBuffer(bytes, 0, bytes.Length);
            using (var awaitable1 = new SocketAwaitable(info))
            {
                await udpSocket.SendToAsync(awaitable1);
            }

            int count;
            var reply = new byte[bufSize];

            // IMPORTANT: follow http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
            var      args   = SocketExtension.EventArgsFactory.Create();
            EndPoint remote = new IPEndPoint(IPAddress.Any, 0);

            try
            {
                args.RemoteEndPoint = remote;
                args.SetBuffer(reply, 0, bufSize);
                using (var awaitable = new SocketAwaitable(args))
                {
                    count = await udpSocket.ReceiveAsync(awaitable);
                }
            }
            catch (SocketException ex)
            {
                // FIXME: If you use a Mono build without the fix for this issue (https://bugzilla.novell.com/show_bug.cgi?id=599488), please uncomment this code.

                /*
                 * if (SnmpMessageExtension.IsRunningOnMono && ex.ErrorCode == 10035)
                 * {
                 *  throw TimeoutException.Create(receiver.Address, timeout);
                 * }
                 * // */

                if (ex.SocketErrorCode == SocketError.TimedOut)
                {
                    throw TimeoutException.Create(receiver.Address, 0);
                }

                throw;
            }

            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
            var response     = MessageFactory.ParseMessages(reply, 0, count, registry)[0];
            var responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                var requestId  = request.MessageId();
                var responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address);
        }
        /// <summary>
        /// Sends an  <see cref="ISnmpMessage"/> and handles the response from agent.
        /// </summary>
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
        /// <param name="timeout">The time-out value, in milliseconds. The default value is 0, which indicates an infinite time-out period. Specifying -1 also indicates an infinite time-out period.</param>
        /// <param name="receiver">Agent.</param>
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
        /// <param name="registry">The user registry.</param>
        /// <returns></returns>
        public static ISnmpMessage GetResponse(this ISnmpMessage request, int timeout, IPEndPoint receiver, UserRegistry registry, Socket udpSocket)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (udpSocket == null)
            {
                throw new ArgumentNullException(nameof(udpSocket));
            }

            if (receiver == null)
            {
                throw new ArgumentNullException(nameof(receiver));
            }

            if (registry == null)
            {
                throw new ArgumentNullException(nameof(registry));
            }

            var requestCode = request.TypeCode();

            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
            }

            var bytes   = request.ToBytes();
            var bufSize = udpSocket.ReceiveBufferSize = Messenger.MaxMessageSize;
            var reply   = new byte[bufSize];

            // Whatever you change, try to keep the Send and the Receive close to each other.
            udpSocket.SendTo(bytes, receiver);
            udpSocket.ReceiveTimeout = timeout;
            int count;

            try
            {
                count = udpSocket.Receive(reply, 0, bufSize, SocketFlags.None);
            }
            catch (SocketException ex)
            {
                // FIXME: If you use a Mono build without the fix for this issue (https://bugzilla.novell.com/show_bug.cgi?id=599488), please uncomment this code.

                /*
                 * if (SnmpMessageExtension.IsRunningOnMono && ex.ErrorCode == 10035)
                 * {
                 *  throw TimeoutException.Create(receiver.Address, timeout);
                 * }
                 * // */

                if (ex.SocketErrorCode == SocketError.TimedOut)
                {
                    throw TimeoutException.Create(receiver.Address, timeout);
                }

                throw;
            }

            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
            var response     = MessageFactory.ParseMessages(reply, 0, count, registry)[0];
            var responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                var requestId  = request.MessageId();
                var responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address);
        }
Esempio n. 11
0
        /// <summary>
        /// Sends an <see cref="ISnmpMessage"/> and handles the response from agent.
        /// </summary>
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
        /// <param name="receiver">Agent.</param>
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
        /// <param name="registry">The user registry.</param>
        /// <returns></returns>
        public static async Task <ISnmpMessage> GetResponseAsync(this ISnmpMessage request, int timeout, IPEndPoint receiver, UserRegistry registry, UdpClient udpSocket /*, int retries = 0*/)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (udpSocket == null)
            {
                throw new ArgumentNullException(nameof(udpSocket));
            }

            if (registry == null)
            {
                throw new ArgumentNullException(nameof(registry));
            }

            var requestCode = request.TypeCode();

            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
            }

            var bytes = request.ToBytes();

            udpSocket.Connect(receiver);
            var recvTask = udpSocket.ReceiveAsync();

            if (timeout > 0)
            {
                var timeoutTask = Task.Delay(timeout);
                await udpSocket.SendAsync(bytes, bytes.Length).ConfigureAwait(false);

                var r = await Task.WhenAny(new Task[] { recvTask, timeoutTask }).ConfigureAwait(false);

                if (r == timeoutTask)
                {
                    udpSocket.Close();
                    throw TimeoutException.Create(receiver.Address, timeout);
                }
            }
            var result = await recvTask.ConfigureAwait(false);

            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
            var response     = MessageFactory.ParseMessages(result.Buffer, 0, result.Buffer.Length, registry)[0];
            var responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                var requestId  = request.MessageId();
                var responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address);
        }
Esempio n. 12
0
 /// <summary>
 /// Returns a <see cref="System.String"/> that represents this instance.
 /// </summary>
 /// <returns>
 /// A <see cref="System.String"/> that represents this instance.
 /// </returns>
 public override string ToString()
 {
     return(string.Format(CultureInfo.InvariantCulture, "discovery class: message id: {0}; request id: {1}", _discovery.MessageId(), _discovery.RequestId()));
 }
Esempio n. 13
0
        /// <summary>
        /// Sends an <see cref="ISnmpMessage"/> and handles the response from agent.
        /// </summary>
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
        /// <param name="receiver">Agent.</param>
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
        /// <param name="registry">The user registry.</param>
        /// <returns></returns>
        public static async Task <ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint receiver, UserRegistry registry, Socket udpSocket, int timeout)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (udpSocket == null)
            {
                throw new ArgumentNullException(nameof(udpSocket));
            }

            if (registry == null)
            {
                throw new ArgumentNullException(nameof(registry));
            }

            var requestCode = request.TypeCode();

            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
            }

            var          bytes = request.ToBytes();
            ISnmpMessage response;

            // Whatever you change, try to keep the Send and the Receive close to each other.

            // fix race condition where the gc memory was corrupted
            using (var udpClient = new UdpClient())
            {
                udpClient.DontFragment = true;
                await udpClient.SendAsync(bytes, bytes.Length, receiver);

                // ReceiveAsync is an extension method implemented in class UdpClientExtension
                // it handles the timeout behavior to avoid object dispose exception when an timeout is received
                // but also - later - a valid datagram
                UdpReceiveResult receiveTask = await udpClient.ReceiveAsync(receiver, timeout);

                byte[] reply = new byte[receiveTask.Buffer.Length];
                receiveTask.Buffer.CopyTo(reply, 0);

                // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
                response = MessageFactory.ParseMessages(reply, 0, reply.Length, registry)[0];
            }

            var responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                var requestId  = request.MessageId();
                var responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address);
        }
Esempio n. 14
0
        public static async Task <ISnmpMessage> GetResponseAsync(this ISnmpMessage request, IPEndPoint receiver, UserRegistry registry, Socket udpSocket, CancellationToken token)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (udpSocket == null)
            {
                throw new ArgumentNullException(nameof(udpSocket));
            }

            if (registry == null)
            {
                throw new ArgumentNullException(nameof(registry));
            }

            var requestCode = request.TypeCode();

            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
            }

            var bytes   = request.ToBytes();
            var bufSize = udpSocket.ReceiveBufferSize = Messenger.MaxMessageSize;

            // Whatever you change, try to keep the Send and the Receive close to each other.
            var buffer = new ArraySegment <byte>(bytes);
            await udpSocket.SendToAsync(buffer, SocketFlags.None, receiver ?? throw new ArgumentNullException(nameof(receiver)), token);

            int count;

            byte[] reply = new byte[bufSize];

            // IMPORTANT: follow http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
            var      remoteAddress = udpSocket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any;
            EndPoint remote        = new IPEndPoint(remoteAddress, 0);

            try
            {
                var result = await udpSocket.ReceiveMessageFromAsync(new ArraySegment <byte>(reply), SocketFlags.None, remote, token);

                count = result.ReceivedBytes;
            }
            catch (SocketException ex)
            {
                // IMPORTANT: Mono behavior (https://bugzilla.novell.com/show_bug.cgi?id=599488)
                if (IsRunningOnMono() && ex.SocketErrorCode == SocketError.WouldBlock)
                {
                    throw TimeoutException.Create(receiver.Address, 0);
                }

                if (ex.SocketErrorCode == SocketError.TimedOut)
                {
                    throw TimeoutException.Create(receiver.Address, 0);
                }

                throw;
            }

            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
            var response     = MessageFactory.ParseMessages(reply, 0, count, registry)[0];
            var responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                var requestId  = request.MessageId();
                var responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address);
        }
Esempio n. 15
0
        /// <summary>
        /// Sends an  <see cref="ISnmpMessage"/> and handles the response from agent.
        /// </summary>
        /// <param name="request">The <see cref="ISnmpMessage"/>.</param>
        /// <param name="timeout">The time-out value, in milliseconds. The default value is 0, which indicates an infinite time-out period. Specifying -1 also indicates an infinite time-out period.</param>
        /// <param name="receiver">Agent.</param>
        /// <param name="udpSocket">The UDP <see cref="Socket"/> to use to send/receive.</param>
        /// <param name="registry">The user registry.</param>
        /// <returns></returns>
        public static ISnmpMessage GetResponse(this ISnmpMessage request, int timeout, IPEndPoint receiver, UserRegistry registry, Socket udpSocket)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (udpSocket == null)
            {
                throw new ArgumentNullException(nameof(udpSocket));
            }

            if (receiver == null)
            {
                throw new ArgumentNullException(nameof(receiver));
            }

            if (registry == null)
            {
                throw new ArgumentNullException(nameof(registry));
            }

            SnmpType requestCode = request.TypeCode();

            if (requestCode == SnmpType.TrapV1Pdu || requestCode == SnmpType.TrapV2Pdu || requestCode == SnmpType.ReportPdu)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "not a request message: {0}", requestCode));
            }

            byte[] bytes   = request.ToBytes();
            int    bufSize = udpSocket.ReceiveBufferSize = Messenger.MaxMessageSize;

            byte[] reply = new byte[bufSize];

            // Whatever you change, try to keep the Send and the Receive close to each other.
            udpSocket.SendTo(bytes, receiver);
            udpSocket.ReceiveTimeout = timeout;
            int count;

            try
            {
                count = udpSocket.Receive(reply, 0, bufSize, SocketFlags.None);
            }
            catch (SocketException ex)
            {
                // IMPORTANT: Mono behavior.
                if (IsRunningOnMono && ex.SocketErrorCode == SocketError.WouldBlock)
                {
                    throw TimeoutException.Create(receiver.Address, timeout);
                }


                if (ex.SocketErrorCode == SocketError.TimedOut)
                {
                    throw TimeoutException.Create(receiver.Address, timeout);
                }

                throw;
            }

            // Passing 'count' is not necessary because ParseMessages should ignore it, but it offer extra safety (and would avoid an issue if parsing >1 response).
            ISnmpMessage response     = MessageFactory.ParseMessages(reply, 0, count, registry)[0];
            SnmpType     responseCode = response.TypeCode();

            if (responseCode == SnmpType.ResponsePdu || responseCode == SnmpType.ReportPdu)
            {
                int requestId  = request.MessageId();
                int responseId = response.MessageId();
                if (responseId != requestId)
                {
                    throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response sequence: expected {0}, received {1}", requestId, responseId), receiver.Address);
                }

                return(response);
            }

            throw OperationException.Create(string.Format(CultureInfo.InvariantCulture, "wrong response type: {0}", responseCode), receiver.Address);
        }