/// <summary> /// Begin an async SNMP request /// </summary> /// <param name="peer">Pdu to send to the agent</param> /// <param name="port">Callback to receive response from the agent</param> /// <param name="buffer">Buffer containing data to send to the peer</param> /// <param name="bufferLength">Length of data in the buffer</param> /// <param name="timeout">Request timeout in milliseconds</param> /// <param name="retries">Maximum retry count. 0 = single request no further retries.</param> /// <param name="asyncCallback">Callback that will receive the status and result of the operation</param> /// <returns>Returns false if another request is already in progress or if socket used by the class /// has been closed using Dispose() member, otherwise true</returns> /// <exception cref="SnmpException">Thrown when IPv4 address is passed to the v6 socket or vice versa</exception> internal bool RequestAsync(IPAddress peer, int port, byte[] buffer, int bufferLength, int timeout, int retries, SnmpAsyncCallback asyncCallback) { if (_busy == true) { return(false); } if (_socket == null) { return(false); // socket has been closed. no new operations are possible. } if (_socket.AddressFamily != peer.AddressFamily) { throw new SnmpException("Invalid address protocol version."); } _busy = true; _asyncCallback = null; _asyncCallback += asyncCallback; _requestState = new AsyncRequestState(peer, port, retries, timeout); _requestState.Packet = buffer; _requestState.PacketLength = bufferLength; // _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, _requestState.Timeout); _inBuffer = new byte[64 * 1024]; // create incoming data buffer SendToBegin(); // Send the request return(true); }
/// <summary> /// Calls async version of the SendTo socket function. /// </summary> internal void SendToBegin() { if (_requestState == null) { _busy = false; return; } // kill the timeout timer - there shouldn't be one active when we are sending a new request if (_requestState.Timer != null) { _requestState.Timer.Dispose(); _requestState.Timer = null; } if (_socket == null) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); return; // socket has been closed. no new operations are possible. } try { _socket.BeginSendTo(_requestState.Packet, 0, _requestState.PacketLength, SocketFlags.None, _requestState.EndPoint, new AsyncCallback(SendToCallback), null); } catch { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketSendError, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); } }
/// <summary> /// Callback member called on completion of BeginSendTo send data operation. /// </summary> /// <param name="ar">Async result</param> internal void SendToCallback(IAsyncResult ar) { if (_socket == null) { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); _busy = false; return; // socket has been closed. no new operations are possible. } int sentLength = 0; try { sentLength = _socket.EndSendTo(ar); } catch { sentLength = 0; } if (sentLength != _requestState.PacketLength) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketSendError, new IPEndPoint(IPAddress.Any, 0), null, 0); } // Start receive timer ReceiveBegin(); // Initialize a receive call }
/// <summary> /// Begin async version of ReceiveFrom member of the socket class. /// </summary> internal void ReceiveBegin() { // kill the timeout timer if (_requestState.Timer != null) { _requestState.Timer.Dispose(); _requestState.Timer = null; } if (_socket == null || !_busy || _requestState == null) { _busy = false; _requestState = null; if (_socket != null) { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint( _socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); } else { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); } return; // socket has been closed. no new operations are possible. } _receivePeer = new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0); EndPoint ep = _receivePeer; try { _socket.BeginReceiveFrom(_inBuffer, 0, _inBuffer.Length, SocketFlags.None, ref ep, ReceiveFromCallback, null); } catch { // retry on every error. this can be done better by evaluating the returned // error value but it's a lot of work and for a non-acked protocol, just send it again // until you reach max retries. RetryAsyncRequest(); return; } _requestState.Timer = new Timer(AsyncRequestTimerCallback, null, _requestState.Timeout, Timeout.Infinite); }
/// <summary> /// Calls async version of the SendTo socket function. /// </summary> internal void SendToBegin() { if (_socket == null) { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); _busy = false; return; // socket has been closed. no new operations are possible. } try { _socket.BeginSendTo(_requestState.Packet, 0, _requestState.PacketLength, SocketFlags.None, _requestState.EndPoint, new AsyncCallback(SendToCallback), null); } catch { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketSendError, new IPEndPoint(IPAddress.Any, 0), null, 0); } }
/// <summary> /// Callback member called on completion of BeginSendTo send data operation. /// </summary> /// <param name="ar">Async result</param> internal void SendToCallback(IAsyncResult ar) { if (_socket == null || !_busy || _requestState == null) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); return; // socket has been closed. no new operations are possible. } var sentLength = 0; try { sentLength = _socket.EndSendTo(ar); } catch (NullReferenceException ex) { ex.GetType(); _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint( _socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); return; } catch { sentLength = 0; } if (sentLength != _requestState.PacketLength) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketSendError, new IPEndPoint( _socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); return; } // Start receive timer ReceiveBegin(); // Initialize a receive call }
/// <summary> /// Internal retry function. Checks if request has reached maximum number of retries and either resends the request if /// not reached, /// or sends request timed-out notification to the caller if maximum retry count has been reached and request has /// failed. /// </summary> internal void RetryAsyncRequest() { // kill the timer if one is active if (_requestState.Timer != null) { _requestState.Timer.Dispose(); _requestState.Timer = null; } if (_socket == null || !_busy || _requestState == null) { _busy = false; _requestState = null; if (_socket != null) { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint( _socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); } else { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); } return; // socket has been closed. no new operations are possible. } // We increment the retry counter before retry count. Initial CurrentRetry value is set to -1 so that // MaxRetries value can be 0 (first request is not counted as a retry). _requestState.CurrentRetry += 1; if (_requestState.CurrentRetry >= _requestState.MaxRetries) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.Timeout, new IPEndPoint( _socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); } else { SendToBegin(); } }
/// <summary> /// Internal callback called as part of Socket.BeginReceiveFrom. Process incoming packets and notify caller /// of results. /// </summary> /// <param name="ar">Async call result used by <seealso cref="Socket.EndReceiveFrom"/></param> internal void ReceiveFromCallback(IAsyncResult ar) { // kill the timer if one is active if (_requestState != null && _requestState.Timer != null) { _requestState.Timer.Dispose(); _requestState.Timer = null; } if (_socket == null || !_busy || _requestState == null) { _busy = false; _requestState = null; if (_socket == null) { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); } else { _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); } return; // socket has been closed. no new operations are possible. } int inlen = 0; EndPoint ep = (EndPoint)_receivePeer; try { inlen = _socket.EndReceiveFrom(ar, ref ep); } catch (SocketException ex) { if (ex.ErrorCode == 10040) { inlen = 0; // Packet too large } else if (ex.ErrorCode == 10050) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10051) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10054) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10064) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10065) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10061) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10060) { inlen = 0; // Connection attempt timed out. Fall through to retry } else { // Assume it is a timeout } } catch (ObjectDisposedException ex) { ex.GetType(); // this is to avoid the compilation warning _asyncCallback(AsyncRequestResult.Terminated, null, null, -1); return; } catch (NullReferenceException ex) { ex.GetType(); // this is to avoid the compilation warning _asyncCallback(AsyncRequestResult.Terminated, null, null, -1); return; } catch (Exception ex) { ex.GetType(); // we don't care what exception happened. We only want to know if we should retry the request inlen = 0; } if (inlen == 0) { RetryAsyncRequest(); } else { // make a copy of the data from the internal buffer byte[] buf = new byte[inlen]; Buffer.BlockCopy(_inBuffer, 0, buf, 0, inlen); _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.NoError, _receivePeer, buf, buf.Length); } }
/// <summary> /// Callback member called on completion of BeginSendTo send data operation. /// </summary> /// <param name="ar">Async result</param> internal void SendToCallback(IAsyncResult ar) { if (_socket == null || ! _busy || _requestState == null) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); return; // socket has been closed. no new operations are possible. } int sentLength = 0; try { sentLength = _socket.EndSendTo(ar); } catch (NullReferenceException ex) { ex.GetType(); _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); return; } catch { sentLength = 0; } if (sentLength != _requestState.PacketLength) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketSendError, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); return; } // Start receive timer ReceiveBegin(); // Initialize a receive call }
/// <summary> /// Internal retry function. Checks if request has reached maximum number of retries and either resends the request if not reached, /// or sends request timed-out notification to the caller if maximum retry count has been reached and request has failed. /// </summary> internal void RetryAsyncRequest() { // kill the timer if one is active if (_requestState.Timer != null) { _requestState.Timer.Dispose(); _requestState.Timer = null; } if (_socket == null || !_busy || _requestState == null) { _busy = false; _requestState = null; if( _socket != null ) _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); else _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); return; // socket has been closed. no new operations are possible. } // We increment the retry counter before retry count. Initial CurrentRetry value is set to -1 so that // MaxRetries value can be 0 (first request is not counted as a retry). _requestState.CurrentRetry += 1; if (_requestState.CurrentRetry >= _requestState.MaxRetries) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.Timeout, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); return; } else { SendToBegin(); } }
/// <summary> /// Begin an async SNMP request /// </summary> /// <param name="peer">Pdu to send to the agent</param> /// <param name="port">Callback to receive response from the agent</param> /// <param name="buffer">Buffer containing data to send to the peer</param> /// <param name="bufferLength">Length of data in the buffer</param> /// <param name="timeout">Request timeout in milliseconds</param> /// <param name="retries">Maximum retry count. 0 = single request no further retries.</param> /// <param name="asyncCallback">Callback that will receive the status and result of the operation</param> /// <returns>Returns false if another request is already in progress or if socket used by the class /// has been closed using Dispose() member, otherwise true</returns> /// <exception cref="SnmpException">Thrown when IPv4 address is passed to the v6 socket or vice versa</exception> internal bool RequestAsync(IPAddress peer, int port, byte[] buffer, int bufferLength, int timeout, int retries, SnmpAsyncCallback asyncCallback) { if (_busy == true) { return false; } if (_socket == null) { return false; // socket has been closed. no new operations are possible. } if (_socket.AddressFamily != peer.AddressFamily) throw new SnmpException("Invalid address protocol version."); _busy = true; _asyncCallback = null; _asyncCallback += asyncCallback; _requestState = new AsyncRequestState(peer, port, retries, timeout); _requestState.Packet = buffer; _requestState.PacketLength = bufferLength; // _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, _requestState.Timeout); _inBuffer = new byte[64 * 1024]; // create incoming data buffer SendToBegin(); // Send the request return true; }
/// <summary> /// Internal callback called as part of Socket.BeginReceiveFrom. Process incoming packets and notify caller /// of results. /// </summary> /// <param name="ar">Async call result used by <seealso cref="Socket.EndReceiveFrom"/></param> internal void ReceiveFromCallback(IAsyncResult ar) { // kill the timer if one is active if (_requestState.Timer != null) { _requestState.Timer.Dispose(); _requestState.Timer = null; } if (_socket == null || !_busy || _requestState == null) { _busy = false; _requestState = null; if( _socket == null ) _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); else _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); return; // socket has been closed. no new operations are possible. } int inlen = 0; EndPoint ep = (EndPoint)_receivePeer; try { inlen = _socket.EndReceiveFrom(ar, ref ep); } catch (SocketException ex) { if (ex.ErrorCode == 10040) { inlen = 0; // Packet too large } else if (ex.ErrorCode == 10050) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10051) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10054) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10064) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10065) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10061) { _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.SocketReceiveError, null, null, -1); return; } else if (ex.ErrorCode == 10060) { inlen = 0; // Connection attempt timed out. Fall through to retry } else { // Assume it is a timeout } } catch (ObjectDisposedException ex) { ex.GetType(); // this is to avoid the compilation warning _asyncCallback(AsyncRequestResult.Terminated, null, null, -1); return; } catch (NullReferenceException ex) { ex.GetType(); // this is to avoid the compilation warning _asyncCallback(AsyncRequestResult.Terminated, null, null, -1); return; } catch (Exception ex) { ex.GetType(); // we don't care what exception happened. We only want to know if we should retry the request inlen = 0; } if (inlen == 0 ) { RetryAsyncRequest(); } else { // make a copy of the data from the internal buffer byte[] buf = new byte[inlen]; Buffer.BlockCopy(_inBuffer, 0, buf, 0, inlen); _busy = false; _requestState = null; _asyncCallback(AsyncRequestResult.NoError, _receivePeer, buf, buf.Length); } }
/// <summary> /// Begin async version of ReceiveFrom member of the socket class. /// </summary> internal void ReceiveBegin() { // kill the timeout timer if(_requestState.Timer != null) { _requestState.Timer.Dispose(); _requestState.Timer = null; } if (_socket == null || !_busy || _requestState == null) { _busy = false; _requestState = null; if( _socket != null ) _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0), null, 0); else _asyncCallback(AsyncRequestResult.Terminated, new IPEndPoint(IPAddress.Any, 0), null, 0); return; // socket has been closed. no new operations are possible. } _receivePeer = new IPEndPoint(_socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0); EndPoint ep = (EndPoint)_receivePeer; try { _socket.BeginReceiveFrom(_inBuffer, 0, _inBuffer.Length, SocketFlags.None, ref ep, new AsyncCallback(ReceiveFromCallback), null); } catch { // retry on every error. this can be done better by evaluating the returned // error value but it's a lot of work and for a non-acked protocol, just send it again // until you reach max retries. RetryAsyncRequest(); return; } _requestState.Timer = new Timer(new TimerCallback(AsyncRequestTimerCallback), null, _requestState.Timeout, System.Threading.Timeout.Infinite); }