예제 #1
0
 public static SocketAwaitable ReceiveAsync(Socket socket,
                                            SocketAwaitable awaitable)
 {
     awaitable.Reset();
     if (!socket.ReceiveAsync(awaitable.m_eventArgs))
     {
         awaitable.m_wasCompleted = true;
     }
     return(awaitable);
 }
예제 #2
0
 public static SocketAwaitable SendToAsync(this Socket socket,
                                           SocketAwaitable awaitable)
 {
     awaitable.Reset();
     if (!socket.SendToAsync(awaitable.m_eventArgs))
     {
         awaitable.m_wasCompleted = true;
     }
     return(awaitable);
 }
예제 #3
0
        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;
                }
            }
        }
예제 #4
0
        /// <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;
                }
            }
        }
예제 #5
0
        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);
                        }
                    }
                }
            }
        }
예제 #6
0
        /// <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);
            }
        }
예제 #7
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)
        {
            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);
        }
예제 #8
0
        /// <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)
                    {
                    }
                }
            }
        }