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); }
/// <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()); }
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); }
/// <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); }
/// <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())); }
/// <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); }
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); }
/// <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); }