Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Apr : Re: writestream() problem..

www.cryer.info
Managed Newsgroup Archive

Re: writestream() problem..

Subject:Re: writestream() problem..
Posted by:"mustafa korkmaz" (no..@none.com)
Date:4 Apr 2007 02:57:16

Yes your approach seems good.
But only one problem.
if one client want to send any package to other it will use like follow as

procedure TForm1.ServerExecute(AThread: TIdPeerThread);
    var
        b: Byte;
        AThread2: TMyPeerThread;
        Stream: TMemoryStream;
    begin
        TMyPeerThread(AThread).SendQueue;

        AThread.Connection.ReadBuffer(b, SizeOf(b));

        if b = 89 then
        begin
            AThread.Connection.ReadBuffer(b, SizeOf(b));
            Nick := AThread.Connection.ReadString(b);

            Stream := TMemoryStream.Create;
            try
                AThread.Connection.ReadStream(Stream);
            except
                Stream.Free;
                raise;
            end;

            AThread2 := FindAThreadFromNick(Nick);
            if (AThread2 <> nil) and AThread2.AddToQueue(Stream) then Exit;

            Stream.Free;
        end
        else
        if b = 90 then
            ...
    end;


"AThread2 := FindAThreadFromNick(Nick);"
"if (AThread2 <> nil) and AThread2.AddToQueue(Stream) then Exit;"

Yes this adds one task to destination queue of Athread.
But destination Athread can not aware this task unless it receives any package..

"TMyPeerThread(AThread).SendQueue;"
"AThread.Connection.ReadBuffer(b, SizeOf(b));"

Because it stays on "AThread.Connection.ReadBuffer(b, SizeOf(b));" line.


Any package must be processed by destination Athread suddenly..Dont have to wait...

Thanks..


"Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> wrote:
>
>"mustafakorkmaz" <mustafakorkmaz@gmail.com> wrote in message
>news:4610b53e$1@newsgroups.borland.com...
>
>> "if Task.Stream.size < 10000 then"
>> What is the meaing of this line?
>> if the size of stream smaller(<) then 10000 send package Else dont
>send.
>> "<" this expression means smaller...
>> Or there is some thing about streams that I dont know.
>
>My mistake.  I thought you were using '>' instead of '<'.
>
>But my earlier statements are still valid, just reversed now.  If the
>stream contains too much data, then none of it will be sent.  So you
>are probably pushing multiple packages, or fewer but larger packages,
>into the stream before sending it, and then none of them are getting
>sent.  So my suggestion to get rid of checking the stream Size
>altogether is still valid.
>
>> This server receive the packages from clients and it reads these
>> packages. And send these packages to all other users or only
>> one user.
>
>Only if the packages are small.  But your receiving code is not
>enforcing that.
>
>> Server reads first byte of the packages and it decide to what
>> must it do? And it writes all data to stream and create one TTask
>> class. And it adds this class to queue of proper writer thread.
>> And writer thread sends this package to receiver.
>> Writer thread takes package from its queue one by one.
>
>Then why are you bothering with checking the stream Size at all?  Each
>Task is a complete package.  It must be sent as-is, or it may never
>get sent at all because your code is restricting it.
>
>Your code is wrong for other reasons, too.  The biggest is that you
>have a buffer overflow vulnerability.  You are allowing the client to
>specify any length it wants for the stream data, but you are not
>validating it before reading the data into your buffer.  Instead of
>using a fixed-length buffer, just read directly into the stream
>instead.  Then you can handle the full length regardless of what it
>is.
>
>Also, you are not doing any error checking in regards to locating the
>Nick to forward the data to.  A package that specifies a non-existant
>user will crash your code because you are not validating anything.
>
>Also, your writer thread does not appear to be using a thread-safe
>list, either.  You really should be.
>
>
>Try this instead:
>
>    procedure TForm1.ServerExecute(AThread: TIdPeerThread);
>    var
>        b: Byte;
>        AThread2: TIdPeerThread;
>        Stream: TMemoryStream;
>        No: Integer;
>        Task: TTask;
>    begin
>        AThread.Connection.ReadBuffer(firstbyte, SizeOf(firstbyte));
>
>        if b = 89 then
>        begin
>            AThread.Connection.ReadBuffer(b, SizeOf(b));
>            Nick := AThread.Connection.ReadString(b);
>
>            Stream := TMemoryStream.Create;
>            try
>                AThread.Connection.ReadStream(Stream); // calls
>ReadInteger() internally
>
>                AThread2 := FindAThreadFromNick(Nick);
>                if AThread2 <> nil then
>                begin
>                    No := FindProperWriterThreadNumber(AThread2);
>                    if No <> -1 then
>                    begin
>                        Task := TTask.Create(AThread2, Stream);
>                        Stream := nil;
>                        try
>                            WriterThreads[No].AddTaskList(Task);
>                        except
>                            Task.Free;
>                            raise;
>                        end;
>                    end;
>                end;
>            except
>                Stream.Free;
>                raise;
>            end;
>        end
>        else
>        if b = 90 then
>            ...
>    end;
>
>
>    procedure TWriterThread.Execute;
>    var
>        Task: TTask;
>        List. TList;
>        Count: Integer;
>    begin
>        While not Terminated do
>        begin
>            Count := 0;
>            try
>                List := MyTaskList.LockList; // MyTaskList is a
>TThreadList now
>                try
>                    while List.Count > 0 do
>                    begin
>                        Task := TTask(MyTaskList[0]);
>                        MyTaskList.Delete(0);
>
>                        try
>                            criticalnumber :=
>TMyClient(Task.AThread.Data).criticalnumber;
>
>
>EnterCriticalSection(CriticalArray[criticalnumber]);
>                            try
>                                waittime := GetTickCount;
>
>Task.AThread.Connection.WriteStream(Task.Stream);
>                                if GetTickDiff(waittime, GetTickCount)
>> 3500 then
>                                    ThreadExceptionToLog(' time:' +
>IntToStr(GetTickDiff(waittime, GetTickCount)) + ' size:' +
>IntToStr(Task.Stream.Size));
>                            finally
>
>LeaveCriticalSection(CriticalArray[criticalnumber]);
>                            end;
>                        finally
>                            Task.Free;
>                        end;
>                    end;
>                finally
>                    Count := List.Count;
>                    MyTaskList.UnlockList;
>                end;
>            except
>            end;
>            if Count = 0 then Sleep(10);
>        end;
>    end;
>
>Now, with all of that said, your use of writer thread arrays, critical
>section arrays, etc is very suspicious and potentially very dangerous
>as you are not using them very safely.  I strongly suggest you
>re-think your design.  A better way would be to derive a new class
>from TIdPeerThread and let it handle its own queuing system locally.
>Then your server code becomes a lot cleaner and safer.  For example:
>
>    type
>        TMyPeerThread = class(TIdPeerThread)
>        private
>            FQueue: TThreadList;
>            FWriteLock: TCriticalSection;
>        public
>            constructor Create(ACreateSuspended: Boolean = True);
>override;
>            destructor Destroy; override;
>            function AddToQueue(Stream: TStream): Boolean;
>            procedure SendQueue;
>        end;
>
>
>    constructor TMyPeerThread.Create(ACreateSuspended: Boolean =
>True);
>    begin
>        inherited;
>        FQueue := TThreadList.Create;
>        FWriteLock := TCriticalSection.Create;
>    end;
>
>    destructor TMyPeerThread.Destroy;
>    var
>        List: TList;
>        I: Integer;
>    begin
>        if FQueue <> nil then
>        begin
>            List := FQueue.LockList;
>            try
>                for I := List.Count-1 do
>                    TStream(List[I]).Free;
>            finally
>                FQueue.UnlockList;
>            end;
>        end;
>        FQueue.Free;
>        FWriteLock.Free;
>        inherited;
>    end;
>
>    function TMyPeerThread.AddToQueue(Stream: TStream): Boolean;
>    begin
>        Result := False;
>        if Stream <> nil then
>        try
>            FQueue.Add(Stream);
>            Result := True;
>        except
>        end;
>    end;
>
>    procedure TMyPeerThread.SendQueue;
>    var
>        List: TList;
>        Stream: TStream;
>        StartTime: Cardinal;
>    begin
>        List := FQueue.LockList;
>        try
>            while List.Count > 0 do
>            begin
>                Stream := TStream(List[0]);
>                List.Delete(0);
>
>                try
>                    FWriteLock.Enter;
>                    try
>                        StartTime := GetTickCount;
>                        Connection.WriteStream(Stream);
>                        if GetTickDiff(StartTime, GetTickCount) > 3500
>then
>                            ThreadExceptionToLog(' time:' +
>IntToStr(GetTickDiff(StartTime, GetTickCount)) + ' size:' +
>IntToStr(Stream.Size));
>                    finally
>                        FWriteLock.Leave;
>                    end;
>                finally
>                    Stream.Free;
>                end;
>            end;
>        finally
>            FQueue.UnlockList;
>        end;
>    end;
>
>
>    constructor TForm1.Create(AOner: TComponent);
>    begin
>        inherited;
>        TCPServer.ThreadClass := TMyPeerThread;
>    end;
>
>    procedure TForm1.ServerExecute(AThread: TIdPeerThread);
>    var
>        b: Byte;
>        AThread2: TMyPeerThread;
>        Stream: TMemoryStream;
>    begin
>        TMyPeerThread(AThread).SendQueue;
>
>        AThread.Connection.ReadBuffer(b, SizeOf(b));
>
>        if b = 89 then
>        begin
>            AThread.Connection.ReadBuffer(b, SizeOf(b));
>            Nick := AThread.Connection.ReadString(b);
>
>            Stream := TMemoryStream.Create;
>            try
>                AThread.Connection.ReadStream(Stream); // calls
>ReadInteger() internally
>            except
>                Stream.Free;
>                raise;
>            end;
>
>            AThread2 := FindAThreadFromNick(Nick);
>            if (AThread2 <> nil) and AThread2.AddToQueue(Stream) then
>Exit;
>
>            Stream.Free;
>        end
>        else
>        if b = 90 then
>            ...
>    end;
>
>
>Gambit

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive