public static SocketAwaitable ReceiveAsync(Socket socket, SocketAwaitable awaitable) { awaitable.Reset(); if (!socket.ReceiveAsync(awaitable.m_eventArgs)) { awaitable.m_wasCompleted = true; } return(awaitable); }
public static SocketAwaitable SendToAsync(this Socket socket, SocketAwaitable awaitable) { awaitable.Reset(); if (!socket.SendToAsync(awaitable.m_eventArgs)) { awaitable.m_wasCompleted = true; } return(awaitable); }
private async Task ReceiveAsync(Socket socket) { while (true) { // If no more active, then stop. if (Interlocked.Exchange(ref _active, _active) == Inactive) { return; } int count; var reply = ArrayPool <byte> .Shared.Rent(_bufferSize); var args = SocketExtension.EventArgsFactory.Create(); try { EndPoint remote = new IPEndPoint(IPAddress.Any, 0); args.RemoteEndPoint = remote; args.SetBuffer(reply, 0, _bufferSize); using (var awaitable = new SocketAwaitable(args)) { count = await socket.ReceiveMessageFromAsync(awaitable); } await Task.Factory .StartNew(() => HandleMessage(reply, count, (IPEndPoint)args.RemoteEndPoint)) .ContinueWith(_ => ArrayPool <byte> .Shared.Return(reply)) .ConfigureAwait(false); } catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.ConnectionReset) { continue; } // If the SnmpTrapListener was active, marks it as stopped and call HandleException. // If it was inactive, the exception is likely to result from this, and we raise nothing. var activeBefore = Interlocked.CompareExchange(ref _active, Inactive, Active); if (activeBefore == Active) { HandleException(ex); } } catch (NullReferenceException) { args.UserToken = SocketAsyncEventArgsFactory.DisposedMessage; } } }
/// <summary> /// Sends a response message. /// </summary> /// <param name="response"> /// A <see cref="ISnmpMessage"/>. /// </param> /// <param name="receiver">Receiver.</param> public async Task SendResponseAsync(ISnmpMessage response, EndPoint receiver) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (response == null) { throw new ArgumentNullException(nameof(response)); } if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } if (_disposed) { throw new ObjectDisposedException("Listener"); } if (_socket == null) { return; } var buffer = response.ToBytes(); var info = SocketExtension.EventArgsFactory.Create(); try { info.RemoteEndPoint = receiver; info.SetBuffer(buffer, 0, buffer.Length); using (var awaitable1 = new SocketAwaitable(info)) { await _socket.SendToAsync(awaitable1); } } catch (SocketException ex) { if (ex.SocketErrorCode != SocketError.Interrupted) { // IMPORTANT: interrupted means the socket is closed. throw; } } }
private async Task ReceiveAsync() { EndPoint remote = _socket.AddressFamily == AddressFamily.InterNetwork ? new IPEndPoint(IPAddress.Any, 0) : new IPEndPoint(IPAddress.IPv6Any, 0); while (true) { // If no more active, then stop. if (Interlocked.Exchange(ref _active, _active) == Inactive) { return; } int count; var reply = new byte[_bufferSize]; var args = SocketExtension.EventArgsFactory.Create(); try { args.RemoteEndPoint = remote; args.SetBuffer(reply, 0, _bufferSize); using (var awaitable = new SocketAwaitable(args)) { count = await _socket.ReceiveAsync(awaitable); } await Task.Factory.StartNew(() => HandleMessage(reply, count, (IPEndPoint)remote)); } catch (SocketException ex) { // ignore WSAECONNRESET, http://bytes.com/topic/c-sharp/answers/237558-strange-udp-socket-problem if (ex.SocketErrorCode != SocketError.ConnectionReset) { // If the SnmpTrapListener was active, marks it as stopped and call HandleException. // If it was inactive, the exception is likely to result from this, and we raise nothing. var activeBefore = Interlocked.CompareExchange(ref _active, Inactive, Active); if (activeBefore == Active) { HandleException(ex); } } } } }
/// <summary> /// Sends an <see cref="ISnmpMessage"/>. /// </summary> /// <param name="message">The <see cref="ISnmpMessage"/>.</param> /// <param name="manager">Manager</param> /// <param name="socket">The socket.</param> public static async Task SendAsync(this ISnmpMessage message, EndPoint manager, Socket socket) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (socket == null) { throw new ArgumentNullException(nameof(socket)); } if (manager == null) { throw new ArgumentNullException(nameof(manager)); } var code = message.TypeCode(); if ((code != SnmpType.TrapV1Pdu && code != SnmpType.TrapV2Pdu) && code != SnmpType.ReportPdu) { throw new InvalidOperationException(string.Format( CultureInfo.InvariantCulture, "not a trap message: {0}", code)); } var bytes = message.ToBytes(); var info = SocketExtension.EventArgsFactory.Create(); info.RemoteEndPoint = manager; info.SetBuffer(bytes, 0, bytes.Length); using (var awaitable1 = new SocketAwaitable(info)) { await socket.SendToAsync(awaitable1); } }
/// <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> /// Discovers agents of the specified version in a specific time interval. /// </summary> /// <param name="version">The version.</param> /// <param name="broadcastAddress">The broadcast address.</param> /// <param name="community">The community.</param> /// <param name="interval">The discovering time interval, in milliseconds.</param> /// <remarks><paramref name="broadcastAddress"/> must be an IPv4 address. IPv6 is not yet supported here.</remarks> public async Task DiscoverAsync(VersionCode version, IPEndPoint broadcastAddress, OctetString community, int interval) { if (broadcastAddress == null) { throw new ArgumentNullException(nameof(broadcastAddress)); } if (version != VersionCode.V3 && community == null) { throw new ArgumentNullException(nameof(community)); } var addressFamily = broadcastAddress.AddressFamily; if (addressFamily == AddressFamily.InterNetworkV6) { throw new ArgumentException("IP v6 is not yet supported.", nameof(broadcastAddress)); } byte[] bytes; _requestId = Messenger.NextRequestId; if (version == VersionCode.V3) { // throw new NotSupportedException("SNMP v3 is not supported"); var discovery = new Discovery(Messenger.NextMessageId, _requestId, Messenger.MaxMessageSize); bytes = discovery.ToBytes(); } else { var message = new GetRequestMessage(_requestId, version, community, _defaultVariables); bytes = message.ToBytes(); } using (var udp = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp)) { udp.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); udp.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true); var info = SocketExtension.EventArgsFactory.Create(); info.RemoteEndPoint = broadcastAddress; info.SetBuffer(bytes, 0, bytes.Length); using (var awaitable1 = new SocketAwaitable(info)) { await udp.SendToAsync(awaitable1); } var activeBefore = Interlocked.CompareExchange(ref _active, Active, Inactive); if (activeBefore == Active) { // If already started, we've nothing to do. return; } _bufferSize = udp.ReceiveBufferSize; await Task.WhenAny( ReceiveAsync(udp), Task.Delay(interval)); Interlocked.CompareExchange(ref _active, Inactive, Active); try { udp.Shutdown(SocketShutdown.Both); } catch (SocketException ex) { // This exception is thrown in .NET Core <=2.1.4 on non-Windows systems. // However, the shutdown call is necessary to release the socket binding. if (!SnmpMessageExtension.IsRunningOnWindows && ex.SocketErrorCode == SocketError.NotConnected) { } } } }