/// <summary> /// Creates a <see cref="TimeoutException"/>. /// </summary> /// <param name="agent">Agent address</param> /// <param name="timeout">Timeout</param> /// <returns></returns> public static TimeoutException Create(IPAddress agent, int timeout) { if (agent == null) { throw new ArgumentNullException(nameof(agent)); } var ex = new TimeoutException($"Request timed out after {timeout}-ms.") { Agent = agent, Timeout = timeout }; return(ex); }
/// <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 (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 ?? throw new ArgumentNullException(nameof(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.ReceiveMessageFromAsync(awaitable); } } 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)); } 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) { // 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). 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); }