// // I/O callback methods // /// <summary> /// <para>Provides a wrapper for the async operations, so that the code can be shared with sync</para> /// </summary> private static void ReadCallback(IAsyncResult asyncResult) { ReceiveState state = (ReceiveState)asyncResult.AsyncState; try { Stream stream = (Stream)state.Connection; int bytesRead = 0; try { bytesRead = stream.EndRead(asyncResult); if (bytesRead == 0) { state.Connection.CloseSocket(); } } catch (IOException) { state.Connection.MarkAsRecoverableFailure(); throw; } catch { throw; } state.Connection.ReceiveCommandResponseCallback(state, bytesRead); } catch (Exception e) { state.Connection.Abort(e); } }
void OnAccept(IAsyncResult asyncResult) { Socket clientSocket = null; try { clientSocket = listenSocket.EndAccept(asyncResult); // Wait for next client this.listenSocket.BeginAccept(OnAccept, null); IPEndPoint clientIp = (IPEndPoint)clientSocket.RemoteEndPoint; Console.WriteLine("Connection from {0}.{1}", clientIp.Address, clientIp.Port); ReceiveState receiveState = new ReceiveState { ClientSocket = clientSocket, Buffer = new byte[4], Offset = 0, Count = 4, ReceivingLength = true, }; clientSocket.BeginReceive(receiveState.Buffer, 0, 4, SocketFlags.None, OnReceive, receiveState); } catch (ObjectDisposedException) { // socket closed } catch (SocketException e) { Console.WriteLine("Socket exception: {0}", e); } }
/// <summary> /// Kicks off an asynchronous or sync request to receive a response from the server. /// Uses the Encoding <code>encoding</code> to transform the bytes received into a string to be /// returned in the GeneralResponseDescription's StatusDescription field. /// </summary> private ResponseDescription ReceiveCommandResponse() { // These are the things that will be needed to maintain state. ReceiveState state = new ReceiveState(this); try { // If a string of nonzero length was decoded from the buffered bytes after the last complete response, then we // will use this string as our first string to append to the response StatusBuffer, and we will // forego a Connection.Receive here. if (_buffer.Length > 0) { ReceiveCommandResponseCallback(state, -1); } else { int bytesRead; try { if (_isAsync) { BeginRead(state.Buffer, 0, state.Buffer.Length, s_readCallbackDelegate, state); return(null); } else { bytesRead = Read(state.Buffer, 0, state.Buffer.Length); if (bytesRead == 0) { CloseSocket(); } ReceiveCommandResponseCallback(state, bytesRead); } } catch (IOException) { MarkAsRecoverableFailure(); throw; } catch { throw; } } } catch (Exception e) { if (e is WebException) { throw; } throw GenerateException(SR.net_ftp_receivefailure, WebExceptionStatus.ReceiveFailure, e); } return(state.Resp); }
private ResponseDescription ReceiveCommandResponse() { ReceiveState state = new ReceiveState(this); try { if (this.m_Buffer.Length > 0) { this.ReceiveCommandResponseCallback(state, -1); } else { try { if (this.m_Async) { this.BeginRead(state.Buffer, 0, state.Buffer.Length, m_ReadCallbackDelegate, state); return(null); } int bytesRead = this.Read(state.Buffer, 0, state.Buffer.Length); if (bytesRead == 0) { base.CloseSocket(); } this.ReceiveCommandResponseCallback(state, bytesRead); } catch (IOException) { this.MarkAsRecoverableFailure(); throw; } catch { throw; } } } catch (Exception exception) { if (exception is WebException) { throw; } throw this.GenerateException(WebExceptionStatus.ReceiveFailure, exception); } return(state.Resp); }
public void BeginHandling() { send = new SocketAsyncEventArgs(); send.Completed += IOCompleted; send.UserToken = new SendToken(); //send.SetBuffer(new byte[BUFFER_SIZE], 0, BUFFER_SIZE); var receive = new SocketAsyncEventArgs(); receive.Completed += IOCompleted; receive.UserToken = new ReceiveToken(); receive.SetBuffer(new byte[BUFFER_SIZE], 0, BUFFER_SIZE); receiveState = ReceiveState.ReceivingHdr; receive.SetBuffer(0, 5); if (!skt.ReceiveAsync(receive)) IOCompleted(this, receive); }
public void BeginHandling() { skt.NoDelay = true; skt.UseOnlyOverlappedIO = true; send = new SocketAsyncEventArgs(); send.Completed += SendCompleted; send.UserToken = new SendToken(); send.SetBuffer(sendBuff = new byte[BUFFER_SIZE], 0, BUFFER_SIZE); receive = new SocketAsyncEventArgs(); receive.Completed += ReceiveCompleted; receive.UserToken = new ReceiveToken(); receive.SetBuffer(receiveBuff = new byte[BUFFER_SIZE], 0, BUFFER_SIZE); receiveState = ReceiveState.ReceivingHdr; receive.SetBuffer(0, 5); if (!skt.ReceiveAsync(receive)) ReceiveCompleted(this, receive); }
public void BeginHandling() { logger.InfoFormat("{0} connected.", skt.RemoteEndPoint); skt.NoDelay = true; skt.UseOnlyOverlappedIO = true; send = new SocketAsyncEventArgs(); send.Completed += IOCompleted; send.UserToken = new SendToken(); send.SetBuffer(new byte[BUFFER_SIZE], 0, BUFFER_SIZE); var receive = new SocketAsyncEventArgs(); receive.Completed += IOCompleted; receive.UserToken = new ReceiveToken(); receive.SetBuffer(new byte[BUFFER_SIZE], 0, BUFFER_SIZE); receiveState = ReceiveState.ReceivingHdr; receive.SetBuffer(0, 5); if (!skt.ReceiveAsync(receive)) IOCompleted(this, receive); }
/// <summary> /// Kicks off an asynchronous or sync request to receive a response from the server. /// Uses the Encoding <code>encoding</code> to transform the bytes received into a string to be /// returned in the GeneralResponseDescription's StatusDescription field. /// </summary> private ResponseDescription ReceiveCommandResponse() { // These are the things that will be needed to maintain state. ReceiveState state = new ReceiveState(this); try { // If a string of nonzero length was decoded from the buffered bytes after the last complete response, then we // will use this string as our first string to append to the response StatusBuffer, and we will // forego a Connection.Receive here. if (_buffer.Length > 0) { ReceiveCommandResponseCallback(state, -1); } else { int bytesRead; try { if (_isAsync) { BeginRead(state.Buffer, 0, state.Buffer.Length, s_readCallbackDelegate, state); return null; } else { bytesRead = Read(state.Buffer, 0, state.Buffer.Length); if (bytesRead == 0) CloseSocket(); ReceiveCommandResponseCallback(state, bytesRead); } } catch (IOException) { MarkAsRecoverableFailure(); throw; } catch { throw; } } } catch (Exception e) { if (e is WebException) throw; throw GenerateException(SR.net_ftp_receivefailure, WebExceptionStatus.ReceiveFailure, e); } return state.Resp; }
void receiveLength(ReceiveState state) { int offset = state == null ? 0 : 1; state = state == null ? new ReceiveState() : state; _socket.BeginReceive(state.len, offset, 2 - offset, SocketFlags.None, _receiveCallback, state); }
void ReceiveCompleted(object sender, SocketAsyncEventArgs e) { try { bool repeat; do { repeat = false; if (e.SocketError != SocketError.Success) throw new SocketException((int)e.SocketError); switch (receiveState) { case ReceiveState.ReceivingHdr: if (e.BytesTransferred < 5) { parent.Disconnect(); return; } if (e.Buffer[0] == 0x3c && e.Buffer[1] == 0x70 && e.Buffer[2] == 0x6f && e.Buffer[3] == 0x6c && e.Buffer[4] == 0x69) { ProcessPolicyFile(); return; } var len = (e.UserToken as ReceiveToken).Length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(e.Buffer, 0)) - 5; if (len < 0 || len > BUFFER_SIZE) throw new InternalBufferOverflowException(); (e.UserToken as ReceiveToken).Packet = Packet.Packets[(PacketID)e.Buffer[4]].CreateInstance(); receiveState = ReceiveState.ReceivingBody; e.SetBuffer(0, len); if (!skt.ReceiveAsync(e)) { repeat = true; continue; } break; case ReceiveState.ReceivingBody: if (e.BytesTransferred < (e.UserToken as ReceiveToken).Length) { parent.Disconnect(); return; } var pkt = (e.UserToken as ReceiveToken).Packet; pkt.Read(parent, e.Buffer, 0, (e.UserToken as ReceiveToken).Length); receiveState = ReceiveState.Processing; bool cont = OnPacketReceived(pkt); if (cont && skt.Connected) { receiveState = ReceiveState.ReceivingHdr; e.SetBuffer(0, 5); if (!skt.ReceiveAsync(e)) { repeat = true; continue; } } break; default: throw new InvalidOperationException(e.LastOperation.ToString()); } } while (repeat); } catch (Exception ex) { OnError(ex); } }
/// <summary> /// Initiate method for asynchronous receive operation of payload data in "payload-aware" mode. /// </summary> private void ReceivePayloadAwareAsync(ReceiveState receiveState) { int length; if (!receiveState.Token.Cancelled) { if (receiveState.PayloadLength < 0) length = m_payloadMarker.Length + Payload.LengthSegment; else length = receiveState.PayloadLength; if (receiveState.Buffer != receiveState.ReceiveArgs.Buffer) receiveState.ReceiveArgs.SetBuffer(receiveState.Buffer, 0, length); else receiveState.ReceiveArgs.SetBuffer(receiveState.Offset, length - receiveState.Offset); if (!receiveState.Socket.ReceiveAsync(receiveState.ReceiveArgs)) ThreadPool.QueueUserWorkItem(state => ProcessReceivePayloadAware(receiveState)); } }
void receiveLength(ReceiveState state) { if (_closing || _disposed) return; int offset = state == null ? 0 : 1; state = state == null ? new ReceiveState() : state; _stream.BeginRead(state.len, offset, 2 - offset, _receiveCallback, state); }
private ResponseDescription ReceiveCommandResponse() { ReceiveState state = new ReceiveState(this); try { if (this.m_Buffer.Length > 0) { this.ReceiveCommandResponseCallback(state, -1); } else { try { if (this.m_Async) { this.BeginRead(state.Buffer, 0, state.Buffer.Length, m_ReadCallbackDelegate, state); return null; } int bytesRead = this.Read(state.Buffer, 0, state.Buffer.Length); if (bytesRead == 0) { base.CloseSocket(); } this.ReceiveCommandResponseCallback(state, bytesRead); } catch (IOException) { this.MarkAsRecoverableFailure(); throw; } catch { throw; } } } catch (Exception exception) { if (exception is WebException) { throw; } throw this.GenerateException(WebExceptionStatus.ReceiveFailure, exception); } return state.Resp; }
/// <summary> /// Kicks off an asynchronous or sync request to receive a response from the server. /// Uses the Encoding <code>encoding</code> to transform the bytes received into a string to be /// returned in the GeneralResponseDescription's StatusDescription field. /// </summary> private ResponseDescription ReceiveCommandResponse() { // These are the things that will be needed to maintain state ReceiveState state = new ReceiveState(this); // If there are any bytes left over in the buffer, then attempt to form a string out of the bytes remaining, decoding it // into a string using the implementor's encoding. if (m_BufferCount > 0) { state.StringFromBuffer = Encoding.GetString(m_Buffer, m_BufferOffset, m_BufferCount); } try { // If a string of nonzero length was decoded from the buffered bytes, then we // will use this string as our first string to append to the response StatusBuffer, and we will // forego a Connection.Receive here. // Note that we get the number of bytes in the byte encoding of the decoded string, in order to determine // how many bytes were used in the string. The number of bytes left in the buffer is decremented by this // amount (this will usually mean buffer count goes to zero) and increment the buffer offset to indicate // that there are a few buffer bytes left over. if (state.StringFromBuffer.Length > 0) { int bytesUsed = Encoding.GetByteCount(state.StringFromBuffer); m_BufferCount -= bytesUsed; m_BufferOffset += bytesUsed; ReceiveCommandResponseCallback(state, -1); } else { int bytesRead; int readOffset = 0; int readLength = state.Buffer.Length; // we didn't get anything out of the buffer - // this means that either the only contents of the buffer were less than a complete character in the encoding, // or that there was nothing in the buffer at all. if (m_BufferCount > 0) { // if there was anything in the buffer, then the buffer contents represent a partial character in the encoding used. // This means that in order to get anything productive done, we need to perform a Receive on the connection in order // to finish at least one character to send to CheckValid. // So copy the remaining contents of the buffer into the beginning of the receive buffer (state.Buffer). // Then try to fill the rest of the buffer with a receive. Buffer.BlockCopy(m_Buffer, m_BufferOffset, state.Buffer, 0, m_BufferCount); state.BytesInBuffer = m_BufferCount; readOffset = m_BufferCount; readLength = state.Buffer.Length - readOffset; m_BufferCount = 0; // buffer is flushed. } try { if (m_Async) { BeginRead(state.Buffer, readOffset, readLength, m_ReadCallbackDelegate, state); return(null); } else { bytesRead = Read(state.Buffer, readOffset, readLength); if (bytesRead == 0) { CloseSocket(); } ReceiveCommandResponseCallback(state, bytesRead); } } catch (IOException) { MarkAsRecoverableFailure(); throw; } catch { throw; } } } catch (Exception e) { if (e is WebException) { throw; } throw GenerateException(WebExceptionStatus.ReceiveFailure, e); } return(state.Resp); }
private void ReceiveMessageLength(IAsyncResult ar) { var receiveState = ar.AsyncState.CastObj<ReceiveState>(); var connectedSocket = receiveState.ConnectedSocket; if (!StillConnected(connectedSocket)) return; var bytesReceived = connectedSocket.EndReceive(ar); if (bytesReceived == 0) throw new Exception("Nothing received"); if (bytesReceived != 4) throw new Exception("Cannot receive message size"); var messageSize = BitConverter.ToInt32(receiveState.Buffer, 0); var buffer = new byte[messageSize]; var nextReceiveState = new ReceiveState { Buffer = buffer, ConnectedSocket = connectedSocket }; connectedSocket.BeginReceive(buffer, 0, buffer.Length, 0, ReceiveMessage, nextReceiveState); }
private void Receive(ReceiveState st) { try { //_log.Debug("MockTcpServer.Receive: Wait for data from Socket connection"); st.socket.BeginReceive(st.buffer, 0, ReceiveState.BufferSize, SocketFlags.None, (ar) => { ReceiveState state = (ReceiveState)ar.AsyncState; int received = state.socket.EndReceive(ar); //_log.Debug(string.Format("MockTcpServer.Receive: Read {0} from Socket connection", received)); if (received > 0) { state.message.AddRange(state.buffer.Take(received).ToList()); Receive(state); // read the remaining } else { //_log.Debug("MockTcpServer.Receive: Read message from Socket connection"); Received.Add(state.message.ToArray()); Receive(new ReceiveState(state.socket)); } }, st); } catch { } }
//It is said that ReceiveAsync/SendAsync never returns false unless error //So...let's just treat it as always true void ReceiveCompleted(object sender, SocketAsyncEventArgs e) { try { if (!skt.Connected) return; if (e.SocketError != SocketError.Success) throw new SocketException((int)e.SocketError); switch (receiveState) { case ReceiveState.ReceivingHdr: if (e.BytesTransferred < 5) { parent.Disconnect(); return; } if (e.Buffer[0] == 0x3c && e.Buffer[1] == 0x70 && e.Buffer[2] == 0x6f && e.Buffer[3] == 0x6c && e.Buffer[4] == 0x69) { ProcessPolicyFile(); return; } var len = (e.UserToken as ReceiveToken).Length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(e.Buffer, 0)) - 5; if (len < 0 || len > BUFFER_SIZE) log.ErrorFormat("Buffer not large enough! (requested size={0})", len); (e.UserToken as ReceiveToken).PacketBody = new byte[len]; (e.UserToken as ReceiveToken).ID = (PacketID)e.Buffer[4]; receiveState = ReceiveState.ReceivingBody; e.SetBuffer(0, len); skt.ReceiveAsync(e); break; case ReceiveState.ReceivingBody: if (e.BytesTransferred < (e.UserToken as ReceiveToken).Length) { parent.Disconnect(); return; } var body = (e.UserToken as ReceiveToken).PacketBody; var id = (e.UserToken as ReceiveToken).ID; Buffer.BlockCopy(e.Buffer, 0, body, 0, body.Length); //pkt.Read(parent, e.Buffer, 0, (e.UserToken as ReceiveToken).Length); receiveState = ReceiveState.Processing; bool cont = OnPacketReceived(id, body); if (cont && skt.Connected) { receiveState = ReceiveState.ReceivingHdr; e.SetBuffer(0, 5); skt.ReceiveAsync(e); } break; default: throw new InvalidOperationException(e.LastOperation.ToString()); } } catch (Exception ex) { OnError(ex); } }
private void Receive(Socket socket) { var buffer = new byte[4]; var receiveState = new ReceiveState { Buffer = buffer, ConnectedSocket = socket }; socket.BeginReceive(buffer, 0, buffer.Length, 0, ReceiveMessageLength, receiveState); }
public void AddEdge(TcpEdge e) { Socket s = e.Socket; AllSockets.Add(s); ReceiveState rs = new ReceiveState(e, BA); _sock_to_rs[s] = rs; Interlocked.Increment(ref TEL._count); }
Task<byte[]> DoReceive(ReceiveState state = null) { try { if (_socket == null) return Task<byte[]>.FromResult(new byte[]{}); if (state == null) state = new ReceiveState(_socket); _socket.BeginReceive(state.buffer, 0, ReceiveState.BufferSize, 0, (ar) => { try { ReceiveState st = (ReceiveState)ar.AsyncState; var t = st.Task; var s = (Socket)t.Task.AsyncState; try { int received = st.socket.EndReceive(ar); if (received > 0) { RaiseDebug("AsyncSocketClient: Received {0}", received); state.message.AddRange(st.buffer.Take(received).ToList()); } if (received < ReceiveState.BufferSize) { var data = st.message.ToArray(); t.TrySetResult(data); if (data.Length > 0) { RaiseDebug("AsyncSocketClient: Received message {0}", data.Length); RaiseReceivedData(data, data.Length); } } else { DoReceive(state).Wait(); // read the remaining } } catch (Exception exc) { RaiseError(exc); t.TrySetException(exc); } } catch (Exception ex) { RaiseError(ex); } }, state); return state.Task.Task; } catch (Exception ex) { RaiseError(ex); return Task<byte[]>.FromResult(new byte[] { }); } }
void receive(ReceiveState state) { if (_closing || _disposed) return; _stream.BeginRead(state.data, state.offset, state.length - state.offset, _receiveCallback, state); }
/// <summary> /// ReceiveCommandResponseCallback is the main "while loop" of the ReceiveCommandResponse function family. /// In general, what is does is perform an EndReceive() to complete the previous retrieval of bytes from the /// server (unless it is using a buffered response) It then processes what is received by using the /// implementing class's CheckValid() function, as described above. If the response is complete, it returns the single complete /// response in the GeneralResponseDescription created in BeginReceiveComamndResponse, and buffers the rest as described above. /// /// If the response is not complete, it issues another Connection.BeginReceive, with callback ReceiveCommandResponse2, /// so the action will continue at the next invocation of ReceiveCommandResponse2. /// </summary> private void ReceiveCommandResponseCallback(ReceiveState state, int bytesRead) { // completeLength will be set to a nonnegative number by CheckValid if the response is complete: // it will set completeLength to the length of a complete response. int completeLength = -1; while (true) { int validThrough = state.ValidThrough; // passed to checkvalid // If we have a Buffered response (ie data was received with the last response that was past the end of that response) // deal with it as if we had just received it now instead of actually doing another receive if (_buffer.Length > 0) { // Append the string we got from the buffer, and flush it out. state.Resp.StatusBuffer.Append(_buffer); _buffer = string.Empty; // invoke checkvalid. if (!CheckValid(state.Resp, ref validThrough, ref completeLength)) { throw GenerateException(SR.net_ftp_protocolerror, WebExceptionStatus.ServerProtocolViolation, null); } } else // we did a Connection.BeginReceive. Note that in this case, all bytes received are in the receive buffer (because bytes from // the buffer were transferred there if necessary { // this indicates the connection was closed. if (bytesRead <= 0) { throw GenerateException(SR.net_ftp_protocolerror, WebExceptionStatus.ServerProtocolViolation, null); } // decode the bytes in the receive buffer into a string, append it to the statusbuffer, and invoke checkvalid. // Decoder automatically takes care of caching partial codepoints at the end of a buffer. char[] chars = new char[_decoder.GetCharCount(state.Buffer, 0, bytesRead)]; int numChars = _decoder.GetChars(state.Buffer, 0, bytesRead, chars, 0, false); string szResponse = new string(chars, 0, numChars); state.Resp.StatusBuffer.Append(szResponse); if (!CheckValid(state.Resp, ref validThrough, ref completeLength)) { throw GenerateException(SR.net_ftp_protocolerror, WebExceptionStatus.ServerProtocolViolation, null); } // If the response is complete, then determine how many characters are left over...these bytes need to be set into Buffer. if (completeLength >= 0) { int unusedChars = state.Resp.StatusBuffer.Length - completeLength; if (unusedChars > 0) { _buffer = szResponse.Substring(szResponse.Length - unusedChars, unusedChars); } } } // Now, in general, if the response is not complete, update the "valid through" length for the efficiency of checkValid, // and perform the next receive. // Note that there may NOT be bytes in the beginning of the receive buffer (even if there were partial characters left over after the // last encoding), because they get tracked in the Decoder. if (completeLength < 0) { state.ValidThrough = validThrough; try { if (_isAsync) { BeginRead(state.Buffer, 0, state.Buffer.Length, s_readCallbackDelegate, state); return; } else { bytesRead = Read(state.Buffer, 0, state.Buffer.Length); if (bytesRead == 0) CloseSocket(); continue; } } catch (IOException) { MarkAsRecoverableFailure(); throw; } catch { throw; } } // The response is completed break; } // Otherwise, we have a complete response. string responseString = state.Resp.StatusBuffer.ToString(); state.Resp.StatusDescription = responseString.Substring(0, completeLength); // Set the StatusDescription to the complete part of the response. Note that the Buffer has already been taken care of above. if (NetEventSource.Log.IsEnabled()) NetEventSource.PrintInfo(NetEventSource.ComponentType.Web, this, string.Format("Received response: {0}", responseString.Substring(0, completeLength - 2))); if (_isAsync) { // Tell who is listening what was received. if (state.Resp != null) { _currentResponseDescription = state.Resp; } Stream stream = null; if (PostReadCommandProcessing(ref stream)) return; ContinueCommandPipeline(); } }
void IOCompleted(object sender, SocketAsyncEventArgs e) { try { bool repeat; do { repeat = false; if (e.SocketError != SocketError.Success) throw new SocketException((int)e.SocketError); if (e.LastOperation == SocketAsyncOperation.Receive) { switch (receiveState) { case ReceiveState.ReceivingHdr: if (e.BytesTransferred < 5) { parent.Disconnect(); return; } var len = (e.UserToken as ReceiveToken).Length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(e.Buffer, 0)) - 5; if (len < 0 || len > BUFFER_SIZE) throw new InternalBufferOverflowException(); (e.UserToken as ReceiveToken).Packet = Packet.Packets[(PacketID)e.Buffer[4]].CreateInstance(); receiveState = ReceiveState.ReceivingBody; e.SetBuffer(0, len); if (!skt.ReceiveAsync(e)) { repeat = true; continue; } break; case ReceiveState.ReceivingBody: if (e.BytesTransferred < (e.UserToken as ReceiveToken).Length) { parent.Disconnect(); return; } var pkt = (e.UserToken as ReceiveToken).Packet; pkt.Read(parent, e.Buffer, (e.UserToken as ReceiveToken).Length); receiveState = ReceiveState.Processing; bool cont = OnPacketReceived(pkt); if (cont) { receiveState = ReceiveState.ReceivingHdr; e.SetBuffer(0, 5); if (!skt.ReceiveAsync(e)) { repeat = true; continue; } } break; default: throw new InvalidOperationException(e.LastOperation.ToString()); } } else if (e.LastOperation == SocketAsyncOperation.Send) { switch (sendState) { case SendState.Ready: var dat = (e.UserToken as SendToken).Packet.Write(parent); sendState = SendState.Sending; e.SetBuffer(dat, 0, dat.Length); if (!skt.SendAsync(e)) { repeat = true; continue; } break; case SendState.Sending: (e.UserToken as SendToken).Packet = null; if (CanSendPacket(e,true)) { repeat = true; continue; } break; default: throw new InvalidOperationException(e.LastOperation.ToString()); } } else throw new InvalidOperationException(e.LastOperation.ToString()); } while (repeat); } catch (Exception ex) { OnError(ex); } }
//It is said that ReceiveAsync/SendAsync never returns false unless error //So...let's just treat it as always true private void ReceiveCompleted(object sender, SocketAsyncEventArgs e) { try { if (!skt.Connected) { parent.Disconnect(); return; } if (e.SocketError != SocketError.Success) throw new SocketException((int) e.SocketError); switch (receiveState) { case ReceiveState.ReceivingHdr: if (e.BytesTransferred < 5) { parent.Disconnect(); return; } if (e.Buffer[0] == 0x4d && e.Buffer[1] == 0x61 && e.Buffer[2] == 0x64 && e.Buffer[3] == 0x65 && e.Buffer[4] == 0xff) { log.InfoFormat("Usage request from: @ {0}.", skt.RemoteEndPoint); byte[] c = Encoding.ASCII.GetBytes(parent.Manager.MaxClients + ":" + parent.Manager.Clients.Count.ToString()); skt.Send(c); return; } if (e.Buffer[0] == 0x3c && e.Buffer[1] == 0x70 && e.Buffer[2] == 0x6f && e.Buffer[3] == 0x6c && e.Buffer[4] == 0x69) { ProcessPolicyFile(); return; } int len = (e.UserToken as ReceiveToken).Length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(e.Buffer, 0)) - 5; if (len < 0 || len > BUFFER_SIZE) throw new InternalBufferOverflowException(); Packet packet = null; try { packet = Packet.Packets[(PacketID)e.Buffer[4]].CreateInstance(); } catch { log.ErrorFormat("Packet ID not found: {0}", e.Buffer[4]); } (e.UserToken as ReceiveToken).Packet = packet; receiveState = ReceiveState.ReceivingBody; e.SetBuffer(0, len); skt.ReceiveAsync(e); break; case ReceiveState.ReceivingBody: if (e.BytesTransferred < (e.UserToken as ReceiveToken).Length) { parent.Disconnect(); return; } Packet pkt = (e.UserToken as ReceiveToken).Packet; pkt.Read(parent, e.Buffer, 0, (e.UserToken as ReceiveToken).Length); receiveState = ReceiveState.Processing; bool cont = OnPacketReceived(pkt); if (cont && skt.Connected) { receiveState = ReceiveState.ReceivingHdr; e.SetBuffer(0, 5); skt.ReceiveAsync(e); } break; default: throw new InvalidOperationException(e.LastOperation.ToString()); } } catch (Exception ex) { OnError(ex); } }
/// <summary> /// Initiate method for asynchronous receive operation of payload data in "payload-unaware" mode. /// </summary> private void ReceivePayloadUnawareAsync(ReceiveState receiveState) { if (!receiveState.Token.Cancelled) { receiveState.ReceiveArgs.SetBuffer(0, ReceiveBufferSize); if (!receiveState.Socket.ReceiveAsync(receiveState.ReceiveArgs)) ThreadPool.QueueUserWorkItem(state => ProcessReceivePayloadUnaware(receiveState)); } }
void receive(ReceiveState state) { _socket.BeginReceive(state.data, state.offset, state.length - state.offset, SocketFlags.None, _receiveCallback, state); }
/// <summary> /// Releases the unmanaged resources used by the <see cref="TcpClient"/> and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if ((object)m_connectState != null) { TerminateConnection(m_connectState.Token); m_connectState.Dispose(); m_connectState = null; } if ((object)m_receiveState != null) { m_receiveState.Dispose(); m_receiveState = null; } if ((object)m_sendState != null) { m_sendState.Dispose(); m_sendState = null; } if ((object)m_connectWaitHandle != null) { m_connectWaitHandle.Set(); m_connectWaitHandle.Dispose(); m_connectWaitHandle = null; } } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } }
/// <summary> /// ReceiveCommandResponseCallback is the main "while loop" of the ReceiveCommandResponse function family. /// In general, what is does is perform an EndReceive() to complete the previous retrieval of bytes from the /// server (unless it is using a buffered response) It then processes what is received by using the /// implementing class's CheckValid() function, as described above. If the response is complete, it returns the single complete /// response in the GeneralResponseDescription created in BeginReceiveComamndResponse, and buffers the rest as described above. /// /// If the resposne is not complete, it issues another Connection.BeginReceive, with callback ReceiveCommandResponse2, /// so the action will continue at the next invocation of ReceiveCommandResponse2. /// </summary> /// <param name="asyncResult"></param> /// private void ReceiveCommandResponseCallback(ReceiveState state, int bytesRead) { // completeLength will be set to a nonnegative number by CheckValid if the response is complete: // it will set completeLength to the length of a complete response. int completeLength = -1; while (true) { int validThrough = state.ValidThrough; // passed to checkvalid // If we got a string from decoding the contents of the Buffered response, then we didn't call BeginReceive, so don't // call end receive... if (state.StringFromBuffer.Length > 0) { // Append the string we got from the buffer, and flush it out. state.Resp.StatusBuffer.Append(state.StringFromBuffer); state.StringFromBuffer = ""; // invoke checkvalid. if (!CheckValid(state.Resp, ref validThrough, ref completeLength)) { throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null); } // if the response is NOT complete, then we'll have to do a Receive. However, there may be // bytes left over in the buffer that were not decoded into the string. // Copy these bytes into the receive buffer so that they will not be lost in the next Receive(). if (completeLength < 0) { Buffer.BlockCopy(m_Buffer, m_BufferOffset, state.Buffer, 0, m_BufferCount); state.BytesInBuffer = m_BufferCount; m_BufferCount = 0; } // else if the response is complete, then we can leave the buffer, possibly with leftover bytes, as is, and all is accurate. // Update the "last length of the statusBuffer" info. state.LastResponseLength += state.StringFromBuffer.Length; } else // we did a Connection.BeginReceive. Note that in this case, all bytes received are in the receive buffer (because bytes from // the buffer were transferred there if necessary { // this indicates the connection was closed. if (bytesRead <= 0) { throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null); } // There may have been bytes in the receive buffer before, so increase the count of bytes by the number read from (receive). state.BytesInBuffer += bytesRead; // decode the bytes in the receive buffer into a string, append it to the statusbuffer, and invoke checkvalid. string szResponse = Encoding.GetString(state.Buffer, 0, state.BytesInBuffer); state.Resp.StatusBuffer.Append(szResponse); if (!CheckValid(state.Resp, ref validThrough, ref completeLength)) { throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null); } // If the response is complete, then determine how many bytes are left over...these bytes need to be set into Buffer. // To do this we see how many characters from the last appended string are used up in the complete response. // This number is completeLength - state.LastResponseLength. Note at every execution of ReceiveCommandresponse2, // the invariant is that the bytes in the receive buffer are exactly those bytes beyond the end of the last status buffer // string, so the encoding in bytes of the status buffer from (state.LastResponseLength) to (completeLength) are those // bytes used from the last string appended, and the rest are to be buffered. if (completeLength >= 0) { if (completeLength < state.LastResponseLength) { throw GenerateException(WebExceptionStatus.ServerProtocolViolation, null); // CompleteLength Too Low } int bytesFromThisReceive = Encoding.GetByteCount(szResponse.Substring(0, completeLength - state.LastResponseLength)); // bytes to buffer if (state.BytesInBuffer > bytesFromThisReceive) { SetBuffer(state.Buffer, bytesFromThisReceive, state.BytesInBuffer - bytesFromThisReceive); } } else // not complete. Any bytes that were not in the string that was appended (szResponse) // are moved to the beginning of the receive buffer so they can be considered in the next Receive(). // this prevents loss of any bytes. { state.LastResponseLength = state.Resp.StatusBuffer.Length; // update the last length of the statusbuffer. int bytesUsed = Encoding.GetByteCount(szResponse); state.BytesInBuffer -= bytesUsed; Buffer.BlockCopy(state.Buffer, bytesUsed, state.Buffer, 0, state.BytesInBuffer); } } // Now, in general, if the response is not complete, update the "valid through" length for the efficiency of checkValid. // and perform the next receive. // Note that there may be bytes in the beginning of the receive buffer (if there were partial characters left over after the // last encoding), so start the receive at state.BytesInBuffer. if (completeLength < 0) { state.ValidThrough = validThrough; try { if (m_Async) { BeginRead(state.Buffer, state.BytesInBuffer, state.Buffer.Length - state.BytesInBuffer, m_ReadCallbackDelegate, state); return; } else { bytesRead = Read(state.Buffer, state.BytesInBuffer, state.Buffer.Length - state.BytesInBuffer); if (bytesRead == 0) { CloseSocket(); } continue; } } catch (IOException) { MarkAsRecoverableFailure(); throw; } catch { throw; } } // the response is completed break; } // Otherwise, we have a complete response. string responseString = state.Resp.StatusBuffer.ToString(); state.Resp.StatusDescription = responseString.Substring(0, completeLength); // set the StatusDescription to the complete part of the response. Note that the Buffer has already been taken care of above. if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_received_response, responseString.Substring(0, completeLength - 2))); } if (m_Async) { // Tell who is listening what was received. if (state.Resp != null) { m_CurrentResponseDescription = state.Resp; } Stream stream = null; if (PostReadCommandProcessing(ref stream)) { return; } ContinueCommandPipeline(); } }
private void ProcessIntegratedSecurityAuthentication(IAsyncResult asyncResult) { ConnectState connectState = null; ReceiveState receiveState = null; SendState sendState = null; try { // Get the connect state from the async result connectState = (ConnectState)asyncResult.AsyncState; // Quit if this connection loop has been cancelled if (connectState.Token.Cancelled) return; try { // Complete the operation to authenticate with the server connectState.NegotiateStream.EndAuthenticateAsClient(asyncResult); } catch (InvalidCredentialException) { if (!m_ignoreInvalidCredentials) throw; } // Initialize the SocketAsyncEventArgs for receive operations connectState.ReceiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); connectState.ReceiveArgs.SetBuffer(new byte[ReceiveBufferSize], 0, ReceiveBufferSize); if (m_payloadAware) connectState.ReceiveArgs.Completed += (sender, args) => ProcessReceivePayloadAware((ReceiveState)args.UserToken); else connectState.ReceiveArgs.Completed += (sender, args) => ProcessReceivePayloadUnaware((ReceiveState)args.UserToken); // Initialize the SocketAsyncEventArgs for send operations connectState.SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); connectState.SendArgs.SetBuffer(new byte[SendBufferSize], 0, SendBufferSize); connectState.SendArgs.Completed += (sender, args) => ProcessSend((SendState)args.UserToken); // Initialize state object for the asynchronous send loop sendState = new SendState(); sendState.Token = connectState.Token; sendState.Socket = connectState.Socket; sendState.ReceiveArgs = connectState.ReceiveArgs; sendState.SendArgs = connectState.SendArgs; sendState.SendArgs.UserToken = sendState; // Store sendState in m_sendState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_sendState = sendState; // Check the state of cancellation one more time before // proceeding to the next step of the connection loop if (connectState.Token.Cancelled) return; // Notify of established connection // and begin receiving data. m_connectWaitHandle.Set(); OnConnectionEstablished(); // Initialize state object for the asynchronous receive loop receiveState = new ReceiveState(); receiveState.Token = connectState.Token; receiveState.Socket = connectState.Socket; receiveState.Buffer = connectState.ReceiveArgs.Buffer; receiveState.ReceiveArgs = connectState.ReceiveArgs; receiveState.ReceiveArgs.UserToken = receiveState; receiveState.SendArgs = connectState.SendArgs; // Store receiveState in m_receiveState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_receiveState = receiveState; // Start receiving data if (m_payloadAware) ReceivePayloadAwareAsync(receiveState); else ReceivePayloadUnawareAsync(receiveState); // Further socket interactions are handled through the SslStream // object, so the SocketAsyncEventArgs is no longer needed connectState.ConnectArgs.Dispose(); } catch (SocketException ex) { // Log exception during connection attempt OnConnectionException(ex); // If connectState is null, we cannot proceed if ((object)connectState == null) return; // If the connection is refused by the server, // keep trying until we reach our maximum connection attempts if (ex.SocketErrorCode == SocketError.ConnectionRefused && (MaxConnectionAttempts == -1 || connectState.ConnectionAttempts < MaxConnectionAttempts)) { try { ConnectAsync(connectState); } catch { TerminateConnection(connectState.Token); } } else { // For any other socket exception, // terminate the connection TerminateConnection(connectState.Token); } } catch (Exception ex) { // Log exception during connection attempt string errorMessage = $"Unable to authenticate connection to server: {ex.Message}"; OnConnectionException(new Exception(errorMessage, ex)); // Terminate the connection if ((object)connectState != null) TerminateConnection(connectState.Token); } finally { if ((object)connectState != null) { // If the operation was cancelled during execution, // make sure to dispose of erroneously allocated resources; // otherwise, dispose of the NegotiateStream which is only used for authentication if (connectState.Token.Cancelled) { connectState.Dispose(); } else { connectState.NetworkStream.Dispose(); connectState.NegotiateStream.Dispose(); } } if ((object)receiveState != null && receiveState.Token.Cancelled) receiveState.Dispose(); if ((object)sendState != null && sendState.Token.Cancelled) sendState.Dispose(); } }
/// <summary> /// Callback method for asynchronous receive operation of payload data in "payload-aware" mode. /// </summary> private void ProcessReceivePayloadAware(ReceiveState receiveState) { try { // Quit if this receive loop has been cancelled if (receiveState.Token.Cancelled) return; // Determine if the server disconnected gracefully if (receiveState.ReceiveArgs.SocketError != SocketError.Success) throw new SocketException((int)receiveState.ReceiveArgs.SocketError); if (receiveState.ReceiveArgs.BytesTransferred == 0) throw new SocketException((int)SocketError.Disconnecting); // Update statistics and bytes received. UpdateBytesReceived(receiveState.ReceiveArgs.BytesTransferred); receiveState.Offset += receiveState.ReceiveArgs.BytesTransferred; if (receiveState.PayloadLength < 0) { // If we haven't parsed the length of the payload yet, attempt to parse it receiveState.PayloadLength = Payload.ExtractLength(receiveState.Buffer, receiveState.Offset, m_payloadMarker); if (receiveState.PayloadLength > 0) { receiveState.Offset = 0; if (receiveState.Buffer.Length < receiveState.PayloadLength) receiveState.Buffer = new byte[receiveState.PayloadLength]; } } else if (receiveState.Offset == receiveState.PayloadLength) { // We've received the entire payload so notify the user OnReceiveDataComplete(receiveState.Buffer, receiveState.PayloadLength); // Reset payload length receiveState.Offset = 0; receiveState.PayloadLength = -1; } // Continue asynchronous loop ReceivePayloadAwareAsync(receiveState); } catch (ObjectDisposedException) { // Make sure connection is terminated when client is disposed. TerminateConnection(receiveState.Token); } catch (SocketException ex) { // Log exception during receive operation OnReceiveDataException(ex); // Terminate connection when socket exception is encountered TerminateConnection(receiveState.Token); } catch (Exception ex) { try { // For any other exception, notify and resume OnReceiveDataException(ex); ReceivePayloadAwareAsync(receiveState); } catch { // Terminate connection if resume fails TerminateConnection(receiveState.Token); } } finally { // If the operation was cancelled during execution, // make sure to dispose of allocated resources if ((object)receiveState != null && receiveState.Token.Cancelled) receiveState.Dispose(); } }
private void ReceiveCommandResponseCallback(ReceiveState state, int bytesRead) { int num2; int completeLength = -1; Label_0002: num2 = state.ValidThrough; if (this.m_Buffer.Length > 0) { state.Resp.StatusBuffer.Append(this.m_Buffer); this.m_Buffer = string.Empty; if (!this.CheckValid(state.Resp, ref num2, ref completeLength)) { throw this.GenerateException(WebExceptionStatus.ServerProtocolViolation, null); } } else { if (bytesRead <= 0) { throw this.GenerateException(WebExceptionStatus.ServerProtocolViolation, null); } char[] chars = new char[this.m_Decoder.GetCharCount(state.Buffer, 0, bytesRead)]; int length = this.m_Decoder.GetChars(state.Buffer, 0, bytesRead, chars, 0, false); string str = new string(chars, 0, length); state.Resp.StatusBuffer.Append(str); if (!this.CheckValid(state.Resp, ref num2, ref completeLength)) { throw this.GenerateException(WebExceptionStatus.ServerProtocolViolation, null); } if (completeLength >= 0) { int num4 = state.Resp.StatusBuffer.Length - completeLength; if (num4 > 0) { this.m_Buffer = str.Substring(str.Length - num4, num4); } } } if (completeLength < 0) { state.ValidThrough = num2; try { if (this.m_Async) { this.BeginRead(state.Buffer, 0, state.Buffer.Length, m_ReadCallbackDelegate, state); return; } bytesRead = this.Read(state.Buffer, 0, state.Buffer.Length); if (bytesRead == 0) { base.CloseSocket(); } goto Label_0002; } catch (IOException) { this.MarkAsRecoverableFailure(); throw; } catch { throw; } } string str2 = state.Resp.StatusBuffer.ToString(); state.Resp.StatusDescription = str2.Substring(0, completeLength); if (Logging.On) { Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_received_response", new object[] { str2.Substring(0, completeLength - 2) })); } if (this.m_Async) { if (state.Resp != null) { this.m_CurrentResponseDescription = state.Resp; } Stream stream = null; if (!this.PostReadCommandProcessing(ref stream)) { this.ContinueCommandPipeline(); } } }
/// <summary> /// Callback method for asynchronous receive operation of payload data in "payload-unaware" mode. /// </summary> private void ProcessReceivePayloadUnaware(ReceiveState receiveState) { try { // Quit if this receive loop has been cancelled if (receiveState.Token.Cancelled) return; if (receiveState.ReceiveArgs.SocketError != SocketError.Success) throw new SocketException((int)receiveState.ReceiveArgs.SocketError); if (receiveState.ReceiveArgs.BytesTransferred == 0) throw new SocketException((int)SocketError.Disconnecting); // Update statistics and bytes received UpdateBytesReceived(receiveState.ReceiveArgs.BytesTransferred); receiveState.PayloadLength = receiveState.ReceiveArgs.BytesTransferred; // Notify of received data and resume receive operation. OnReceiveDataComplete(receiveState.Buffer, receiveState.PayloadLength); ReceivePayloadUnawareAsync(receiveState); } catch (ObjectDisposedException) { // Make sure connection is terminated when client is disposed TerminateConnection(receiveState.Token); } catch (SocketException ex) { // Log exception during receive operation OnReceiveDataException(ex); // Terminate connection when socket exception is encountered TerminateConnection(receiveState.Token); } catch (Exception ex) { try { // For any other exception, notify and resume OnReceiveDataException(ex); ReceivePayloadUnawareAsync(receiveState); } catch { // Terminate connection if resume fails TerminateConnection(receiveState.Token); } } }
/// <summary> /// Callback method for asynchronous authenticate operation. /// </summary> private void ProcessTlsAuthentication(IAsyncResult asyncResult) { ConnectState connectState = null; ReceiveState receiveState = null; SendState sendState = null; try { // Get the connect state from the async result connectState = (ConnectState)asyncResult.AsyncState; // Quit if this connection loop has been cancelled if (connectState.Token.Cancelled) return; // Complete the operation to authenticate with the server connectState.SslStream.EndAuthenticateAsClient(asyncResult); // Ensure that this client is authenticated and encrypted if (EnabledSslProtocols != SslProtocols.None) { if (!connectState.SslStream.IsAuthenticated) throw new InvalidOperationException("Connection could not be established because we could not authenticate with the server."); if (!connectState.SslStream.IsEncrypted) throw new InvalidOperationException("Connection could not be established because the data stream is not encrypted."); } if (m_integratedSecurity) { #if !MONO // Check the state of cancellation one more time before // proceeding to the next step of the connection loop if (connectState.Token.Cancelled) return; // Create the NegotiateStream to begin authentication of the user's Windows credentials connectState.NegotiateStream = new NegotiateStream(connectState.SslStream, true); connectState.NegotiateStream.BeginAuthenticateAsClient(m_networkCredential ?? (NetworkCredential)CredentialCache.DefaultCredentials, string.Empty, ProcessIntegratedSecurityAuthentication, connectState); #endif } else { // Initialize state object for the asynchronous send loop sendState = new SendState(); sendState.Socket = connectState.Socket; sendState.NetworkStream = connectState.NetworkStream; sendState.SslStream = connectState.SslStream; sendState.Token = connectState.Token; // Store sendState in m_sendState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_sendState = sendState; // Check the state of cancellation one more time before // proceeding to the next step of the connection loop if (connectState.Token.Cancelled) return; // Notify of established connection m_connectWaitHandle.Set(); OnConnectionEstablished(); // Initialize state object for the asynchronous receive loop receiveState = new ReceiveState(); receiveState.Socket = connectState.Socket; receiveState.NetworkStream = connectState.NetworkStream; receiveState.SslStream = connectState.SslStream; receiveState.Buffer = new byte[m_payloadMarker.Length + Payload.LengthSegment]; receiveState.Token = connectState.Token; // Store receiveState in m_receiveState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_receiveState = receiveState; // Start receiving data if (m_payloadAware) ReceivePayloadAwareAsync(receiveState); else ReceivePayloadUnawareAsync(receiveState); // Further socket interactions are handled through the SslStream // object, so the SocketAsyncEventArgs is no longer needed connectState.ConnectArgs.Dispose(); } } catch (SocketException ex) { // Log exception during connection attempt OnConnectionException(ex); // If connectState is null, we cannot proceed if ((object)connectState == null) return; // If the connection is refused by the server, // keep trying until we reach our maximum connection attempts if (ex.SocketErrorCode == SocketError.ConnectionRefused && (MaxConnectionAttempts == -1 || connectState.ConnectionAttempts < MaxConnectionAttempts)) { try { ConnectAsync(connectState); } catch { TerminateConnection(connectState.Token); } } else { // For any other socket exception, // terminate the connection TerminateConnection(connectState.Token); } } catch (Exception ex) { // Log exception during connection attempt string errorMessage = string.Format("Unable to authenticate connection to server: {0}", CertificateChecker.ReasonForFailure ?? ex.Message); OnConnectionException(new Exception(errorMessage, ex)); // Terminate the connection if ((object)connectState != null) TerminateConnection(connectState.Token); } finally { // If the operation was cancelled during execution, // make sure to dispose of erroneously allocated resources if ((object)connectState != null && connectState.Token.Cancelled) connectState.Dispose(); if ((object)receiveState != null && receiveState.Token.Cancelled) receiveState.Dispose(); if ((object)sendState != null && sendState.Token.Cancelled) sendState.Dispose(); } }
/// <summary> /// Callback method for asynchronous connect operation. /// </summary> private void ProcessConnect(ConnectState connectState) { ReceiveState receiveState = null; SendState sendState = null; try { // Quit if this connection loop has been cancelled if (connectState.Token.Cancelled) return; // Increment the number of connection attempts that // have occurred in this asynchronous connection loop connectState.ConnectionAttempts++; // Check the SocketAsyncEventArgs for errors during the asynchronous connection attempt if (connectState.ConnectArgs.SocketError != SocketError.Success) throw new SocketException((int)connectState.ConnectArgs.SocketError); // Set the size of the buffer used by the socket to store incoming data from the server connectState.Socket.ReceiveBufferSize = ReceiveBufferSize; if (m_integratedSecurity) { #if !MONO // Check the state of cancellation one more time before // proceeding to the next step of the connection loop if (connectState.Token.Cancelled) return; // Create the SslStream object used to perform // send and receive operations on the socket connectState.NetworkStream = new NetworkStream(connectState.Socket, false); connectState.NegotiateStream = new NegotiateStream(connectState.NetworkStream, true); connectState.NegotiateStream.BeginAuthenticateAsClient(m_networkCredential ?? (NetworkCredential)CredentialCache.DefaultCredentials, string.Empty, ProcessIntegratedSecurityAuthentication, connectState); #endif } else { // Initialize the SocketAsyncEventArgs for receive operations connectState.ReceiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); connectState.ReceiveArgs.SetBuffer(new byte[ReceiveBufferSize], 0, ReceiveBufferSize); if (m_payloadAware) connectState.ReceiveArgs.Completed += (sender, args) => ProcessReceivePayloadAware((ReceiveState)args.UserToken); else connectState.ReceiveArgs.Completed += (sender, args) => ProcessReceivePayloadUnaware((ReceiveState)args.UserToken); // Initialize the SocketAsyncEventArgs for send operations connectState.SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(); connectState.SendArgs.SetBuffer(new byte[SendBufferSize], 0, SendBufferSize); connectState.SendArgs.Completed += (sender, args) => ProcessSend((SendState)args.UserToken); // Initialize state object for the asynchronous send loop sendState = new SendState(); sendState.Token = connectState.Token; sendState.Socket = connectState.Socket; sendState.ReceiveArgs = connectState.ReceiveArgs; sendState.SendArgs = connectState.SendArgs; sendState.SendArgs.UserToken = sendState; // Store sendState in m_sendState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_sendState = sendState; // Check the state of cancellation one more time before // proceeding to the next step of the connection loop if (connectState.Token.Cancelled) return; // Notify of established connection m_connectWaitHandle.Set(); OnConnectionEstablished(); // Initialize state object for the asynchronous receive loop receiveState = new ReceiveState(); receiveState.Token = connectState.Token; receiveState.Socket = connectState.Socket; receiveState.Buffer = connectState.ReceiveArgs.Buffer; receiveState.ReceiveArgs = connectState.ReceiveArgs; receiveState.ReceiveArgs.UserToken = receiveState; receiveState.SendArgs = connectState.SendArgs; // Store receiveState in m_receiveState so that calls to Disconnect // and Dispose can dispose resources and cancel asynchronous loops m_receiveState = receiveState; // Start receiving data if (m_payloadAware) ReceivePayloadAwareAsync(receiveState); else ReceivePayloadUnawareAsync(receiveState); // Further socket interactions are handled through the ReceiveArgs // and SendArgs objects, so the ConnectArgs is no longer needed connectState.ConnectArgs.Dispose(); } } catch (SocketException ex) { // Log exception during connection attempt OnConnectionException(ex); // If the connection is refused by the server, // keep trying until we reach our maximum connection attempts if (ex.SocketErrorCode == SocketError.ConnectionRefused && (MaxConnectionAttempts == -1 || connectState.ConnectionAttempts < MaxConnectionAttempts)) { // Server is unavailable, so keep retrying connection to the server. try { ConnectAsync(connectState); } catch { TerminateConnection(connectState.Token); } } else { // For any other reason, clean-up as if the client was disconnected. TerminateConnection(connectState.Token); } } catch (Exception ex) { // Log exception during connection attempt OnConnectionException(ex); // Terminate the connection TerminateConnection(connectState.Token); } finally { // If the operation was cancelled during execution, // make sure to dispose of erroneously allocated resources if ((object)connectState != null && connectState.Token.Cancelled) connectState.Dispose(); if ((object)receiveState != null && receiveState.Token.Cancelled) receiveState.Dispose(); if ((object)sendState != null && sendState.Token.Cancelled) sendState.Dispose(); } }
/// <summary> /// ReceiveCommandResponseCallback is the main "while loop" of the ReceiveCommandResponse function family. /// In general, what is does is perform an EndReceive() to complete the previous retrieval of bytes from the /// server (unless it is using a buffered response) It then processes what is received by using the /// implementing class's CheckValid() function, as described above. If the response is complete, it returns the single complete /// response in the GeneralResponseDescription created in BeginReceiveComamndResponse, and buffers the rest as described above. /// /// If the response is not complete, it issues another Connection.BeginReceive, with callback ReceiveCommandResponse2, /// so the action will continue at the next invocation of ReceiveCommandResponse2. /// </summary> private void ReceiveCommandResponseCallback(ReceiveState state, int bytesRead) { // completeLength will be set to a nonnegative number by CheckValid if the response is complete: // it will set completeLength to the length of a complete response. int completeLength = -1; while (true) { int validThrough = state.ValidThrough; // passed to checkvalid // If we have a Buffered response (ie data was received with the last response that was past the end of that response) // deal with it as if we had just received it now instead of actually doing another receive if (_buffer.Length > 0) { // Append the string we got from the buffer, and flush it out. state.Resp.StatusBuffer.Append(_buffer); _buffer = string.Empty; // invoke checkvalid. if (!CheckValid(state.Resp, ref validThrough, ref completeLength)) { throw GenerateException(SR.net_ftp_protocolerror, WebExceptionStatus.ServerProtocolViolation, null); } } else // we did a Connection.BeginReceive. Note that in this case, all bytes received are in the receive buffer (because bytes from // the buffer were transferred there if necessary { // this indicates the connection was closed. if (bytesRead <= 0) { throw GenerateException(SR.net_ftp_protocolerror, WebExceptionStatus.ServerProtocolViolation, null); } // decode the bytes in the receive buffer into a string, append it to the statusbuffer, and invoke checkvalid. // Decoder automatically takes care of caching partial codepoints at the end of a buffer. char[] chars = new char[_decoder.GetCharCount(state.Buffer, 0, bytesRead)]; int numChars = _decoder.GetChars(state.Buffer, 0, bytesRead, chars, 0, false); string szResponse = new string(chars, 0, numChars); state.Resp.StatusBuffer.Append(szResponse); if (!CheckValid(state.Resp, ref validThrough, ref completeLength)) { throw GenerateException(SR.net_ftp_protocolerror, WebExceptionStatus.ServerProtocolViolation, null); } // If the response is complete, then determine how many characters are left over...these bytes need to be set into Buffer. if (completeLength >= 0) { int unusedChars = state.Resp.StatusBuffer.Length - completeLength; if (unusedChars > 0) { _buffer = szResponse.Substring(szResponse.Length - unusedChars, unusedChars); } } } // Now, in general, if the response is not complete, update the "valid through" length for the efficiency of checkValid, // and perform the next receive. // Note that there may NOT be bytes in the beginning of the receive buffer (even if there were partial characters left over after the // last encoding), because they get tracked in the Decoder. if (completeLength < 0) { state.ValidThrough = validThrough; try { if (_isAsync) { BeginRead(state.Buffer, 0, state.Buffer.Length, s_readCallbackDelegate, state); return; } else { bytesRead = Read(state.Buffer, 0, state.Buffer.Length); if (bytesRead == 0) { CloseSocket(); } continue; } } catch (IOException) { MarkAsRecoverableFailure(); throw; } catch { throw; } } // The response is completed break; } // Otherwise, we have a complete response. string responseString = state.Resp.StatusBuffer.ToString(); state.Resp.StatusDescription = responseString.Substring(0, completeLength); // Set the StatusDescription to the complete part of the response. Note that the Buffer has already been taken care of above. if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"Received response: {responseString.Substring(0, completeLength - 2)}"); } if (_isAsync) { // Tell who is listening what was received. if (state.Resp != null) { _currentResponseDescription = state.Resp; } Stream stream = null; if (PostReadCommandProcessing(ref stream)) { return; } ContinueCommandPipeline(); } }
private void IOCompleted(object sender, SocketAsyncEventArgs e) { try { bool repeat; do { repeat = false; if (e.SocketError != SocketError.Success) throw new SocketException((int) e.SocketError); /* SocketError errorCode; int nBytesRec = Socket.EndReceive(ar, out errorCode); if (errorCode != SocketError.Success) { nBytesRec = 0; } */ if (e.LastOperation == SocketAsyncOperation.Receive) { switch (receiveState) { case ReceiveState.ReceivingHdr: if (debug) Console.WriteLine(@"test"); if (e.BytesTransferred < 5) { parent.Disconnect(); return; } if (debug) Console.WriteLine(@"test2"); if (e.Buffer[0] == 0x3c && e.Buffer[1] == 0x70 && e.Buffer[2] == 0x6f && e.Buffer[3] == 0x6c && e.Buffer[4] == 0x69) { ProcessPolicyFile(); return; } var len = (e.UserToken as ReceiveToken).Length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(e.Buffer, 0)) - 5; if (len < 0 || len > BUFFER_SIZE) throw new InternalBufferOverflowException(); (e.UserToken as ReceiveToken).Packet = Packet.Packets[(PacketID) e.Buffer[4]].CreateInstance(); if (debug) Console.WriteLine("test3 - " + (e.UserToken as ReceiveToken).Packet.GetType().Name); receiveState = ReceiveState.ReceivingBody; e.SetBuffer(0, len); if (!skt.ReceiveAsync(e)) { repeat = true; } break; case ReceiveState.ReceivingBody: if (e.BytesTransferred < (e.UserToken as ReceiveToken).Length) { parent.Disconnect(); return; } var pkt = (e.UserToken as ReceiveToken).Packet; pkt.Read(parent, e.Buffer, (e.UserToken as ReceiveToken).Length); receiveState = ReceiveState.Processing; var cont = OnPacketReceived(pkt); if (cont && skt.Connected) { receiveState = ReceiveState.ReceivingHdr; e.SetBuffer(0, 5); if (!skt.ReceiveAsync(e)) { repeat = true; } } break; default: throw new InvalidOperationException(e.LastOperation.ToString()); } } else if (e.LastOperation == SocketAsyncOperation.Send) { switch (sendState) { case SendState.Ready: var dat = (e.UserToken as SendToken).Packet.Write(parent); sendState = SendState.Sending; e.SetBuffer(dat, 0, dat.Length); if (!skt.SendAsync(e)) { repeat = true; } break; case SendState.Sending: (e.UserToken as SendToken).Packet = null; if (CanSendPacket(e, true)) { repeat = true; } break; default: throw new InvalidOperationException(e.LastOperation.ToString()); } } else throw new InvalidOperationException(e.LastOperation.ToString()); } while (repeat); } catch (Exception ex) { OnError(ex); } }