Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Nov : Re: Input Buffer empty

www.cryer.info
Managed Newsgroup Archive

Re: Input Buffer empty

Subject:Re: Input Buffer empty
Posted by:"Larry Killen" (lkill..@charter.net)
Date:Wed, 5 Dec 2007 19:51:48

Okay, I'll do the dance again.

Here is the call stack leading up to the exception....

ReadOutfeedGSE.TReadingOutfeedThread.Execute  <= Call stack

procedure TReadingOutfeedThread.Execute;  <= procedure (last of my code)
begin
  while not Terminated do
  begin
    FConn.IOHandler.WaitFor(chr(2));
    FBuffer := FConn.IOHandler.ReadLn(chr(3));
    ProcessData;
  end;
end;


IdIOHandler.WaitFor(#2,True,False,en7Bit)  <= Call stack

function TIdIOHandler.WaitFor(const AString: string; ARemoveFromBuffer:
Boolean = True;  <= procedure
  AInclusive: Boolean = False; const AEncoding: TIdEncoding = en7Bit):
string;
  //TODO: Add a time out (default to infinite) and event to pass data
  //TODO: Add a max size argument as well.
  //TODO: Add a case insensitive option
var
  LBytes: TIdBytes;
  LPos: Integer;
begin
  Result := '';
  LBytes := ToBytes(AString, AEncoding);
  LPos := 0;
  repeat
    if CheckForDataOnSource(250) then begin
      LPos := InputBuffer.IndexOf(LBytes, LPos);
      if LPos <> -1 then begin
        if ARemoveFromBuffer and AInclusive then begin
          Result := InputBuffer.Extract(LPos+Length(LBytes), AEncoding);
        end else begin
          if AInclusive then begin
            Result := InputBuffer.Extract(LPos, AEncoding) + AString;
          end else begin
            Result := InputBuffer.Extract(LPos, AEncoding);
          end;
          if ARemoveFromBuffer then begin
            InputBuffer.Remove(Length(LBytes));
          end;
        end;
        Break;
      end;
      LPos := IndyMax(0, InputBuffer.Size - (Length(LBytes)-1));
    end;
    CheckForDisconnect;
  until False;
end;


TIdIOHandler.CheckForDataOnSource(0)  <= Call stack

function TIdIOHandler.CheckForDataOnSource(ATimeout: Integer = 0): Boolean;
<= procedure
begin
  // return whether at least 1 byte was received
  Result := False;
  if Connected then begin
    Result := ReadFromSource(False, ATimeout, False) > 0;
  end;
end;


IdIOHandler.ReadFromSource(False,250,False) <== Call Stack

function TIdIOHandler.ReadFromSource(ARaiseExceptionIfDisconnected: Boolean;
<== Related Procedure
  ATimeout: Integer; ARaiseExceptionOnTimeout: Boolean): Integer;
var
  LByteCount: Integer;
  LLastError: Integer;
  LBuffer: TIdBytes;
begin
  if ATimeout = IdTimeoutDefault then begin
    // MtW: check for 0 too, for compatibility
    if (ReadTimeout = IdTimeoutDefault) or (ReadTimeout = 0) then begin
      ATimeout := IdTimeoutInfinite;
    end else begin
      ATimeout := ReadTimeout;
    end;
  end;
  Result := 0;
  // Check here as this side may have closed the socket
  CheckForDisconnect(ARaiseExceptionIfDisconnected);
  if SourceIsAvailable then begin
    LByteCount := 0;
    repeat
      if Readable(ATimeout) then begin
        if Opened then begin
          // No need to call AntiFreeze, the Readable does that.
          if SourceIsAvailable then begin
            // TODO: Whey are we reallocating LBuffer every time? This
should
            // be a one time operation per connection.
            SetLength(LBuffer, RecvBufferSize); try
              LByteCount := ReadDataFromSource(LBuffer);
              if LByteCount > 0 then begin
                SetLength(LBuffer, LByteCount);
                if Intercept <> nil then begin
                  Intercept.Receive(LBuffer);
                  LByteCount := Length(LBuffer);
                end;
    //AsciiFilter - needs to go in TIdIOHandler base class
    //            if ASCIIFilter then begin
    //              for i := 1 to IOHandler.RecvBuffer.Size do begin
    //                PChar(IOHandler.RecvBuffer.Memory)[i] :=
Chr(Ord(PChar(IOHandler.RecvBuffer.Memory)[i]) and $7F);
    //              end;
    //            end;
                // Pass through LBuffer first so it can go through Intercept
                //TODO: If not intercept, we can skip this step
                InputBuffer.Write(LBuffer);
              end;
            finally LBuffer := nil; end;
          end else begin
            EIdClosedSocket.Toss(RSStatusDisconnected);
          end;
        end else begin
          LByteCount := 0;
          EIdNotConnected.IfTrue(ARaiseExceptionIfDisconnected,
RSNotConnected);
        end;
        if LByteCount < 0 then
        begin
          LLastError := GStack.CheckForSocketError(LByteCount,
[Id_WSAESHUTDOWN, Id_WSAECONNABORTED]);
          FClosedGracefully := True;
          Close;
          // Do not raise unless all data has been read by the user
          if InputBufferIsEmpty then begin
            GStack.RaiseSocketError(LLastError);
          end;
          LByteCount := 0;
        end;
        if LByteCount = 0 then begin
          FClosedGracefully := True;
        end;
        // Check here as other side may have closed connection
        CheckForDisconnect(ARaiseExceptionIfDisconnected);
        Result := LByteCount;
      end else begin
        // Timeout
        EIdReadTimeout.IfTrue(ARaiseExceptionOnTimeout, RSReadTimeout);
        Result := -1;
        Break;
      end;
    until (LByteCount <> 0) or (not SourceIsAvailable);
  end
  else if ARaiseExceptionIfDisconnected then begin
    raise EIdException.Create(RSNotConnected);
  end;
end;


IdIOHandlerStack.TIdIOHandlerStack.CheckForDisconnect(False, True)<== Call
Stack

procedure TIdIOHandlerStack.CheckForDisconnect(    <<==Related Procedure
  ARaiseExceptionIfDisconnected: Boolean; AIgnoreBuffer: Boolean);
var
  LDisconnected: Boolean;
begin
  // ClosedGracefully // Server disconnected
  // IOHandler = nil // Client disconnected
  if ClosedGracefully then begin
    if BindingAllocated then begin
      Close;
      // Call event handlers to inform the user that we were disconnected
      DoStatus(hsDisconnected);
      //DoOnDisconnected;
    end;
    LDisconnected := True;
  end else begin
    LDisconnected := not BindingAllocated;
  end;
  // Do not raise unless all data has been read by the user
  if LDisconnected then begin
    if (InputBufferIsEmpty or AIgnoreBuffer) and
ARaiseExceptionIfDisconnected then begin
      RaiseConnClosedGracefully;
    end;
  end;
end;

IdIOHandler.TIdIOHandler.InputBufferIsEmpty  <<== Call stack

function TIdIOHandler.InputBufferIsEmpty: Boolean; <<== related procedure
begin
  Result := FInputBuffer.Size = 0;
end;

and then the raised exception

AND THAT IS EXACTLY WHAT I AM SEEING!!

"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message
news:4747205b@newsgroups.borland.com...
>
> "Larry Killen" <lkillen@charter.net> wrote in message
> news:4745f63a$1@newsgroups.borland.com...
>
>> I recently started getting occasional InputBufferIsEmpty exceptions.
>
> There are no exceptions for that function.
>
> What exactly are you seeing?
>
>> Below is the procedure I use to read the socket.  I don't
>> know how it could be empty since it is triggered by data.
>
> No, it is not.  It is triggered by a continuous loop that has nothing to
> do
> with whether data is actually avalable or not.
>
>
> Gambit

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive