Delphi 7 and Indy 9 writing data from TCPServer - delphi

I have a Delphi program which sits as a server receiving data and sending back small acknowledgement packets. I previously used this code (edited for brevity)
procedure TdmServer.OnExecuteTCPServer(AThread: TIdPeerThread);
var
IncomingPacket : string;
ResponsePacket : string;
begin
IncomingPacket := AThread.Connection.Readln(#$03);
if IncomingPacket <> '' then
begin
ResponsePacket := ProcessTelegram(IncomingPacket);
AThread.Connection.writeln(ResponsePacket);
end;
AThread.Connection.Disconnect;
end;
This almost works fine, apart from appending an end of line CRLF as it sends, which the client (not under my control) doesn't like.
So I changed it to:
AThread.Connection.Write(ResponsePacket);
and nothing is received on the client.
Then I tried
AThread.Connection.WriteBuffer(ResponsePacket, length(ResponsePacket), true);
to try and get it to write immediately, but it still doesn't send at all.
I have put in delays, tried opening the buffer, flushing and closing it again (like the help file), but still no joy and any time FlushWriteBuffer is called I get an AV.
I'm stuck. Please could anyone offer any words of wisdom?

ReadLn() strips off the terminator from its Result. Is your ProcessTelegram() accounting for that? If it needs the terminator, you will have to add it back in manually, eg:
ProcessTelegram(IncomingPacket + #03)
Is ResponsePacket being formatted correctly for what the client is expecting? If the client is not expecting a terminating CRLF, then using Write() instead of WriteLn() is the correct thing to do.
If you use WriteBuffer(), you must dereference a String in order to pass the correct data address to WriteBuffer(), eg:
WriteBuffer(ResponsePacket[1], Length(ResponsePacket), True)
Or:
WriteBuffer(PChar(ResponsePacket)^, Length(ResponsePacket), True)
If the client is still not receiving the response correctly, then either you are not sending anything at all, or you are not sending the terminator that the client is expecting. Use a packet sniffer, such as Wireshark, to see what the client is actually receiving, if anything.

Related

Advanced look at HTTP headers

Is it possible to read the HTTP headers (specifically the GET header) in the Indy TIdHTTPServer.OnConnect event without interfering with the subsequent OnCommandGet event?
If I try to pull them with a loop of ReadLn's then OnCommandGet never fires. I need an advanced peek at them without pulling them from the input buffer.
Is it possible to read the HTTP headers (specifically the GET header) in the Indy TIdHTTPServer.OnConnect event without interfering with the subsequent OnCommandGet event?
It it possible, in that you could use the TIdIOHandler.WaitFor() method to wait for the header terminator to arrive in the TIdIOHandler.InputBuffer, returning everything received before it without removing anything from the buffer, eg:
procedure TMyForm.IdHTTPServer1Connect(AContext: TIdContext);
var
headers: String;
begin
header := AContext.Connection.IOHandler.WaitFor(EOL+EOL, False);
...
end;
However, this has some limitations:
it assumes each line is terminated by the byte sequence $0D $0A and thus the header is terminated by the byte sequence $0D $0A $0D $0A. This is technically true per the HTTP standards, and will usually be the case. However, some clients do terminate lines with just $0A and thus the header would be terminated by $0A $0A. TIdHTTPServer would normally handle that just fine, but using WaitFor() would not.
A more robust solution would involve using TIdIOHandler.CheckForDataOnSource() in a loop, manually scanning the TIdIOHandler.InputBuffer until either $0D $0A $0D $0A or $0A $0A is found in the buffer.
this won't work if there are multiple HTTP requests on the same connection, which can happen if HTTP keep-alives or HTTP pipelining are used. You would be "peeking" the header of only the 1st HTTP request on the connection.
If I try to pull them with a loop of ReadLn's then OnCommandGet never fires.
Correct, because TIdHTTPServer expects to be the one to read them off the InputBuffer. If you read them yourself beforehand, there won't be anything left for TIdHTTPServer to read, so it won't know what each HTTP request even looks like.
I need an advanced peek at them without pulling them from the input buffer.
Why? What do you want to do with them, if you could get them?
You should check if the TIdHTTPServer.OnHeadersAvailable event suits your needs. It is fired at the beginning of every HTTP request, after the headers have been read from the InputBuffer but before the request body has been read.
I got it working by peeking at the Inputbuffer per Remy's suggestion:
procedure TForm1.IdHTTPServer1Connect(AContext: TIdContext);
var
s: string;
Done: boolean;
begin
Done := False;
repeat
Sleep(10);
if AContext.Connection.IOHandler.CheckForDataOnSource then
begin
s := AContext.Connection.IOHandler.InputBuffer.AsString;
if (Pos(#13#10#13#10, s) > 0) or (Pos(#10#10, s) > 0) then Done := True;
end;
until Done;
...
end;
One issue I could see happening is a bot making a TCP connection on my port and that loop never ending since no headers are coming. I would need to add some kind of timeout check.
The other suggestion of using OnHeadersAvailable wouldn't work for me because it's called right before OnCommandGet each time (i.e., multiple times per connection when KeepAlive is True) so I might as well just put tests in OnCommandGet if I went that route.
EDIT:
I also just tried doing this in the OnConnect handler:
s := AContext.Connection.IOHandler.WaitFor(#10, False, True, nil, 1000);
Since I only need the GET line and it will always be first (right?) if it's included at all, I just need to find the first line feed character. That solves the line terminator problem and there's a timeout parameter that solves the bot issue. While this does read the first line header, it also causes an immediate disconnect and CommandGet never gets called. What am I doing wrong?

Cant seem to recive a reply vir com port

Im trying to send a command to a dev. board and then receive a reply
E.G
(me) set attrib=yes
(Dev. Board) O.K
or
(Dev. Board) E.R.R
But it doesn't bounce back anything ... not an O.K or an E.R.R
while the board is booting echo is on .. so if I send the commands while the board is booting it
it will bounce back an 'set attrib=yes' and once booted an 'E.R.R' because you cant send commands while booting.
my best guess is that it isn't reading the reply in time or trying to read it too soon.
procedure TReaderProgrammer.Button2Click(Sender: TObject);
Var
Buffer: AnsiString;
RxData: string;
Count : integer;
begin
if ComPort1.Connected then
begin
ComPort1.WriteStr(edtSendText.Text+#13);
comport1.ReadStr(RxData,Count);
Buffer := Buffer + Rxdata;
memoRxData.Text := memoRxData.Text+Buffer+#13+#10;
end;
end;
Here are several open questions in the air, so I have to make some assumptions that might be wrong, but let's see.
I don't know what comm port library you are using, so I'm assuming it is the CPort library from SourceForge. I have never used it myself, but I have read that it is made Unicode aware, such that you can call the write methods with a unicodestring parameter which will be converted by the library to ansistring before sending. Similarily when receiving ansistring from the outer world, the library will convert to unicodestring for the Read methods.
Due to the asynchronous nature of serial communication, it is important to understand that when you send something using the write method, the method returns immediately while the library and OS spit out the characters one at at time at a pace defined by the baud rate. As a result your first code never received anything, because you were already attempting to read from the comm port before the external device even received the first character.
It is good to see that you have now taken the first step to success by implementing an event handler for (presumably library event) OnRxChar.
The OnRxChar probably fires for each character (or couple of characters). You need to have a buffer that is persistent between these events. A local var (as you have it now and which is allocated on the stack) in the event handler is not persistent, it is lost every time the event handler exits.
You should declare the Buffer variable as a field of TReaderProgrammer. I don't know why you defined the buffer to be AnsiString, but I suggest you try with string (ref discussion above regarding Unicode awareness).
type
TReaderProgrammer = class
..
RxBuffer: string;
..
end;
The buffer needs to be cleared when you send a new command to the external device in order for it to be ready to receive new data as a response to your command.
EDIT: Alternatively you can clear the RxBuffer immediately when you have received and processed a full response.
The TReaderProgrammer.ComPort1RxChar should look like this sofar:
procedure TReaderProgrammer.ComPort1RxChar(Sender: TObject; Count: Integer);
var
RxData : string;
begin
(Sender as TComPort).ReadStr(RxData,Count);
RxBuffer := RxBuffer + Rxdata;
...
end;
The rest of the event handler is, I guess, probably just to see progress of reception, so nothing more about that.

Need a sample/demo of using TIdTelnet to interact with telnet server

I tried to employ Indy 10.5.5 (shipped with Delphi 2010) for:
connecting to telnet server
performing username/password authentication (gaining access to the command shell)
executing a command with returning resulting data back to application
and had no success, additionally i'm completely lost in spaghetti logic of Indy's internals and now have no idea why it didnt work or how i supposed to send strings to the server and grab the results. Need some sample code to study.
Formal form of the question: Where can i get 3-rd party contributed demo covering TIdTelnet component? (indyproject.org demos webpage do not have one)
The main problem with Telnet is that it DOES NOT utilize a command/response model like most other Internet protocols do. Either party can send data at any time, and each direction of data is independant from the other direction. This is reflected in TIdTelnet by the fact that it runs an internal reading thread to receive data. Because of this, you cannot simply connect, send a command, and wait for a response in a single block of code like you can with other Indy components. You have to write the command, then wait for the OnDataAvailable event to fire, and then parse the data to determine what it actually is (and be prepared to handle situations where partial data may be received, since that is just how TCP/IP works).
If you are connecting to a server that actually implements a command/response model, then you are better off using TIdTCPClient directly instead of TIdTelnet (and then implement any Telnet sequence decoding manually if the server really is using Telnet, which is rare nowadays but not impossible). For Indy 11, we might refactor TIdTelnet's logic to support a non-threaded version, but that is undecided yet.
done with indy.
no comments.. just som old code :-)
telnet don't like the send string kommand.. use sendch.
telnetdude.Host := 1.1.1.1;
try
telnetdude.connect;
except
on E: Exception do begin
E.CleanupInstance;
end; {except}
if telnetdude.Connected then begin
for i := 1 to length(StringToSend) do telnetdude.sendch(StringToSend[i]);
telnetdude.sendch(#13);
end;
end; {while}
end; {if}
if telnetdude.Connected then telnetdude.Disconnect;
end;
I hope this helps anyone looking for answers to a similar question.
Firstly, It would seem the typical command/response model (as mentioned above, does indeed NOT apply).
So I just got it working for some very simple application (rebooting my router).
Specific additions to above code from Johnny Lanewood (and perhaps some clarification)
a) You have to send #13 to confirm the command
b) I got "hangs" on every command I sent / response I requested UNTIL I enabled ThreadedEvent. (this was my big issue)
c) the OnDataAvailable event tells you when new data is available from the Telnet Server - however there are no guarantees as to what this data is - i.e. it's pretty what you get in the command line / what ever is appended to the previous responses. But is is NOT a specific response line to your command - it's whatever the telnet server returns (could be welcome info, ASCII drawings etc etc.)
Given (c) above, one would rather check the OnDataAvailable event and parse the data (knowing what you'd expect). When the output stops (i.e. you need build a mechanism for this), you can parse the data and determine whether the server is ready for something new from the client. For the purpose of my code below, I set a read timemout and I just used Sleep(2000) - ignorantly expecting no errors and that the server would be ready after the sleep for the next command.
My biggest stumbling block was ThreadedEvent := True (see above in b)
Thus, my working solution (for specific application, and possibly horrible to some).
lIDTelnet := TIdTelnet.Create(nil);
try
lIdTelnet.ReadTimeout := 30000;
lIDTelnet.OnDataAvailable := TDummy.Response;
lIDTelnet.OnStatus := TDummy.Status;
lIdTelnet.ThreadedEvent := True;
try
lIDTelnet.Connect('192.168.0.1', 23);
if not lIDTelnet.Connected then
Raise Exception.Create('192.168.0.1 TELNET Connection Failed');
Sleep(2000);
lIdtelnet.SendString(cst_user + #13);
Sleep(2000);
lIdtelnet.SendString(cst_pass + #13);
Sleep(2000);
lIdtelnet.SendString(cst_reboot + #13);
Sleep(2000);
if lIDTelnet.Connected then
lIDTelnet.Disconnect;
except
//Do some handling
end;
finally
FreeAndNil(lIdTelnet);
end;
and then
class procedure TDummy.Response(Sender: TIdTelnet; const Buffer: TIdBytes);
begin
Write(TDummy.ByteToString(Buffer));
end;
class function TDummy.ByteToString(
const aBytes: TIdBytes): String;
var
i : integer;
begin
result := '';
for i := 0 to Length(aBytes) -1 do
begin
result := result + Char(aBytes[i]);
end;
end;

Handling TUdpSocket

I'm trying to use the TUdpSocket in Delphi. What I want to do is connect to a UDP server, send some data and wait for answer. Data is sent correctly, but the control does not receive anything. I don't know why. I've been struggling with this problem for many hours now and I'm going to give up :-(.
I tried to use TIdUDPClient, but the situation is the same. Data is sent properly, but none is received.
Only does TIdUDPServer work more or less properly for it both sends and receives data. Unfortunately data reception is handled by a separate thread (main or other, depending on the ThreadedEvent property) which forces me to use synchronization and complicate the whole code. I would like to handle UDP connection in my own thread. Just send some data and call WaitForData() to wait for an answer and then handle it in the same thread.
And if opossible, I don't want to use any third party controls, but if it is the only solution, I accept it.
Thank you very, very much for your help in advance.
---- Examples ---
i) TUDPSocket:
var
lR, lW, lE: boolean;
begin
UdpSocket1.LocalPort := '1600';
UdpSocket1.RemotePort := '1600';
UdpSocket1.RemoteHost := '127.0.0.1';
UdpSocket1.Connect;
UdpSocket1.Sendln('test');
UdpSocket1.Select(#lR, #lW, #lE, 2000);
if lR then
ShowMessage(UdpSocket1.Receiveln());
end;
As you can see, the control should receive the data it transmits. And apparently it does, for the lR evaluates to true after the Select() method is called. But Receiveln() returns an empty string, as ReceiveBuf() does. When i start a UDP server and send some data to it, it is received properly, so I'm certain that the data is really sent.
You should need nothing more than this:
function SayHi(Host: String; Port: Integer): String;
var
Client: TIdUDPClient;
begin
Client := TIdUDPClient.Create(nil);
try
Client.Host := Host;
Client.Port := Port;
Client.Send('Hello');
Result := Client.ReceiveString(1000);
finally
Client.Free;
end;
end;
which will, in the same thread, send a UDP packet and either receive a UDP packet or raise an exception after a timeout.
If the above doesn't work, check (using something like Wireshark that the client's actually sending the data. Then check on the server that it's actually receiving the packet.
Send() ultimately (on Windows) calls WinSock's sendto(), and ReceiveString() uses select() and recvfrom(). You could sort've simulate a TIdUDPServer by
while not Terminated do begin
S := Client.ReceiveString(1000);
DoSomething(S);
end;
Another possibility would be to use Synapse for your communication. It is a simple communications library which performs blocking calls, so works well in a single worker thread where you want to stop and wait for data rather than rely on an event to fire. The latest versions in SVN have support for the latest versions of Delphi.

problems sending picture from client to server

i am trying to send a picture from 'C:\picture.bmp' to 'c:\temp\picture.bmp' using server and client socket
clients onconnect event handler is as follow:
procedure TForm2.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
var
fs : tfilestream;
begin
fs := TFileStream.create('C:\picture.bmp', fmOpenRead);//picture allready exists
socket.SendStream(fs);
fs.free;
end;
and servers onclientread as :
procedure TForm2.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
fmm : tfilestream;
iLen: Integer;
Bfr: Pointer;
begin
iLen := Socket.ReceiveLength;
GetMem(Bfr, iLen);
fmm := TFileStream.Create('c:\temp\picture.bmp', fmCreate or
fmShareDenyWrite);
try
Socket.ReceiveBuf(Bfr^, iLen);
fmm.Write(Bfr^, iLen);
finally
FreeMem(Bfr);
fmm.Free;
end;
end;
picture is recieved/created but is either corrupt on was never recieved i.e created because of tfilestream.create method?
please help!what am i doing wrong?
Despite its name, SendStream() is NOT guaranteed to send the entire stream (especially if you are using a non-blocking socket). Its return value returns how many bytes are actually sent. If less than the full size of the stream are sent in one call, you have to call SendStream() again, potentially many times, to finish sending the entire stream (the same problems exists with SendText() as well).
On the other side, ReceiveLength() only reports how many bytes are available on the socket AT THAT MOMENT. That is likely to be less than the full stream being sent (likewise, ReceiveText() may not receive a full sent string either because it uses ReceiveLength() internally).
The best way to send a stream (or any arbitrary data in general) is to send the data's size first, then send the actual data afterwards. Keep calling SendBuf/Stream/Text() until that size is reached (if -1 is returned by a non-blocking socket without raising an exception, you have to wait for the socket's OnWrite event to trigger before the socket can accept more data again). On the receiving end, read the size first, then keep reading until the specified size is reached. You may have to read in multiple triggering of the OnRead event before you get all of the data.
Go to http://www.deja.com and http://forums.embarcadero.com to search the Borland/CodeGear/Embarcadero newsgroup/forum archives. I have posted example code many times before.
I don't know what's wrong, but I'd try troubleshooting a simpler problem. i.e. can you even transfer somethign simple? See if you can transfer c:\hello.txt containing just "Hello" and have it arrive in the right order. It should be easier to examine the stream and resulting file, to see if/where things are getting garbled. If you don't receive "Hello" on the server, then you know it's got nothing to do with the size or complexity of the data.

Resources