[interfacekit] Re: BSession
- From: Adi Oanca <adioanca@xxxxxxxxx>
- To: interfacekit@xxxxxxxxxxxxx
- Date: Sun, 18 Apr 2004 01:01:02 +0300
Hello!
Pahtz wrote:
Hi Adi. Thanks for explaining things.
Sure. n.p.
The "int32 code" parameter is NOT the BMessage's "what".
Nope! It IS! See Looper.cpp's:
ReadRawFromPort,
ReadMessageFromPort,
ConvertToMessage
methods.
A system message with no buffer data IS a valid BMessage.
Ok, so it is used differently. Sometimes it is 'what', sometimes it is for the
protocol. This is
confusing but perhaps unavoidable. You have to read the implementation to be
sure. By using it two
ways we fail to establish a convention for others to follow.
No. why?
BMessages and BSession messages should NOT be mixed! They serve
different purposes!
BMessages are designed to work with BLoopers.
BSession is a lightweight protocol without the, IMHO, small overhead
that a BMessage imposes. Also it is streamlined not message_specific
oriented.
DO NOT mix the two. They were not designed to work together. DW wanted
to unify them, but, in the end there is no reason to do that. BSession
is specific for BWindow/BView and for nothing else. I _do not_ agree
enhancing BSession! It serves its purpose!
In the beginning was PortLink, then came along BSession. When Marc
finished BPicture implementation, AreaLink appeared. There was a debate
why not to use PortLink over BSession, and I and DW had long talks about
that. The fact is, PortLink is message oriented and BSession not
streamed, and we need that.
OK, the trade-offs are thus:
You chunk (combine multiple messages) so the server might be able get a second
message without
waiting on the port queue semaphore. It's optimized for small messages. The
(unlikely) non-optimal
scenario is a stream of messages larger than 1024 bytes.
I have already explained you. There is no problem. That server gets to
work with the data it has received in the first BSession message(chunk).
And, there aren't individual messages bigger than 1024.
You fragment so you can flush at will so don't have to dynamically resize the
buffer to avoid
overflow.
Right. Also we avoid lots of memcpy(s).
Original PortLink implementation had the possibility to produce
messages with unlimited size (2M limited by kernel) but after a serious
discussion on this list it was redesigned to use a 4096bytes buffer. So
you see... BSession... PortLink... both have a limited buffer. And here
comes the advantage of BSession: it automatically flushes when the
buffer fills in.
There are may additions that can be introduced to BSession like the
buffer size, but as I said, it only serves one purpose and it does it
very well.
You lose message boundaries in the deal, but you're going to fix that...
Yes... eventually.
ATM everything is working just fine with this method in server.
IF, someone tries to unify those will go into serious problems, because
of the handler. I mean, if you have a handler that is mainly oriented on
PortMessage/PortLink and you send a message with BSession, you will run
into BIIIIIG trouble because BSession messages are NOT complete! The
other way a BSession handler and sending with PortLink, no problem
appears(as you have noticed, in PortLink already there is a method for
sending to BSession hander) but a lot of code needs to be modified;
Is the potential BIIIIIG trouble reason to finish the details before using it everywhere?
What do you mean? As I said: it is used *only* by BWindow/BView. I
suggest creating your own protocol for your needs, or use the excellent
BMessage(/BLooper).
BSession is ready. The only thing that remains to be done is, as
observed by Stefano, pointed out by Axel and forgotten by me :-), to
verify for B_INTERRUPTED.
This thread and your reply serves as documentation for the rest of us.
I will [sometime] write documentation for app_server.
None, just summarising. Although I might fix the memory management bugs, buffer
overflow exploit,
and error detection in PortMessage ;-)
Talk to DW.
I don't see the advantage of this since the server shouldn't
execute a command until it has checked all the parameters.
When I wrote the about I mean like:
Read Command: DRAW_LINE
Read Parameter: x1
Read Parameter: y1
Read Parameter: x2
Read Parameter: y2
Execute(DRAW_LINE, x1, y1, x2, y2);
All parameters will eventually arrive.
What is you problem here?
:-))) Wrong! While the client side buffer is filling in (BSession's
one) app_server is executing drawing instructions. There is a high
probability that, by the time the next write_port() is made and the
message reaches the server, the previous commands be already executed.
Eh? What do you say about that? Nice, isn't it?
The advantage comes from client-server not from BSession's buffering.
And without buffering won't be there excessive context switching?
Infact, while the client side is buffering multiple commands, the server could be sitting idle.
Again: excessive context switching - Sending many small commands would
alternate between server and client execution.
Better let each one: execute/buffer, until its timeslice ends.
It's worth noting that the port mechanism already gives you a port queue for buffering.
yup. that's why we have to do it ourself.
Oh... think if you had PortLink instead of BSession in BWindow/BView?
Would you have seen something drawn until BView::Draw() ended? What
about if you do a lots of things inside Draw(), how big would have the
message been? how long it would have taken for the server to execute
instruction found inside? Same is valuable when attaching a large BView
tree.
I detect communication problems...I don't know if we're agreeing or disagreeing.
Commands could be write_port'ed one by one for speed or grouped for efficiency.
"efficiency"... In the end it's still speed.
What I object to
is fragmenting a command. Each write_port() should deal with complete messages.
AS_DRAW_POINT
x
y
12 bytes in total. do you suggest me make a write_port()? What about
your attitude about context switching?
I saw in your reply to Marcus' email that finally understood what it
all about. Am I right?
If you want to avoid flicker then the user shouldn't see a BView being drawn
command by command.
So you would optimize for minimal total drawing time, rather than try and get
the first command of
many drawn as soon as possible -- assuming you want double
buffered/vtrace/vblank drawing as
default on the appserver.
But we don't have double buffering on the app_server. And in that case
flicker is assured to be eliminated, not by sending all drawing commands
at once but by the double buffering technique itself. Drawing will still
be made in the same fashion, it's just it will be made in an offscreen
surface.
Also BSession had all the return error codes removed. I'm unable to create
robust software
with it.
void BSession::ReadData( void* data, int32 size );
void BSession::WriteData(const void* data, int32 size);
void BSession::Sync();
Yes, I have added them, then removed. I no longer need them.
a
code = AS_NO_MESSAGE;
ses->ReadInt32(&code)
would tell me if something went wrong. This case... the port has been
deleted.
So you have to remember to reset "code" to AS_NO_MESSAGE, and assume that
nothing will actually
send an int32 with the value of AS_NO_MESSAGE,
Yes. AS_NO_MESSAGE is(will be) private.
and you have to get a reply to know whether or not
your send was sucessful. If you don't get a reply, you won't know if it's a
problem with your
send, or a problem with the server replying.
ses->WriteInt32(COMMAND_1);
ses->WriteInt32(PARAMETER_1);
ses->WriteInt32(COMMAND_2);
ses->ReadInt32(&REPLY_1);
If for some reason WriteInt32(COMMAND_1); failed, then PARAMETER_1 might be
interpreted by the
server as COMMAND_3 and COMMAND_2 as a parameter.
Then I get REPLY_1 and assume that both COMMAND_1 and COMMAND_2 were sucessfully processed.
What other reason ReadData() has to fail?
So if I put error codes to be returned, do you think I am going to
check for every Write/Read if it was successful of not? :-| Look how may
Read/Write calls are in Window.cpp/View.cpp and app_Server.
No. I know if it fails if means something had gone terribly wrong and I
have to exit the thread. Eventually the thread will reach its main loop,
the "main" ReadXXXX will fail an the thread will exit.
Another example, internal to BSession:
char* BSession::ReadString(){
int16 len = 0;
char *str = NULL;
ReadData( &len, sizeof(int16));
if (len > 0){
str = (char*)malloc(len+1);
if(str){
ReadData(str, len);
str[len-1] = '\0';
}
}
return str;
}
Good we remembered to initialise len = 0.
We ReadData() the length of the string correctly, it is 80.
The third-party application crashes before the string could be written.
We ReadData(str, len) on an invalid port.
The code returns str as non-null.
Our server printf's the unterminated buffer and segfaults.
Or maybe uses some bogus data to corrupt something important.
Congratulations you just discovered a bug.
It may work if we code perfectly, but it's not defensive programming.
Yes. You're right.
Why do you need to use BSession? it is private!
Besides the fact I hack on more than one appserver, the Java, Python, and
BePascal groups may
eventually want to interface directly with the appserver.
Hmmm... They should take the code from Window.cpp/View.cpp exactly as
it is.
No, all datas will be dumped until the next code is recognized.
I know about this... and I had in plan to suffix each instruction
with... AS_END_INSTRUCTION.
But some parameter may have the value of AS_END_INSTRUCTION.
It does not matter. This is the same as DISABLE/ENABLE_UPDATES.
It is expected.
In 99.99999% of cases this won't happen. Unless a bad user or program
will write to a ServerWindow port. I have discussed this with Michael
and he said it is not concerned by security.
Bad users will be happy that we didn't secure the most obvious exploits.
Bad third-party programs
are a fact of life. Bugs are inevitable. You never know where the problem could
cascade to. It's
bad design.
Do you have a better solution? I'm listening.
As developers of appserver we ourselves will find it hard to debug. We will
have a lot of
incomplete code and changing protocols. We have to disable BWindow sending X
notification
eventhough we've implemented it because the appserver isn't ready to deal with
message X, and
sending it will de-synchronize our stream.
Yes, you are right. These things should be well known by app_server
developers. Again, do you have a better solution?
Sorry but it is the only one suited for BWindow/BView <-> app_server
communication. It worked perfectly until now and I don't see any
problems appearing. Hell... Be used it, and look what a nice graphical
interface R5 has.
Do we really need BSession?
Yup!
Considering the trade-offs, I need more persuasion.
Neither I agree very much with BSession. In fact I do have in mind a
better solution for BWindow/BView <-> app_Server communication, but at
this moment BSession is working very nice and we are have other things
to do.
Bye,
Adi.
---------------------------------------------------------------
Lucram pentru tine. Analizam. Cautam zilnic.
Alegem ceea ce te intereseaza. Te anuntam.
http://www.REDUCERI.ro/
- References:
- [interfacekit] Re: BSession
- From: Pahtz
Other related posts:
- » [interfacekit] BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
- » [interfacekit] Re: BSession
The "int32 code" parameter is NOT the BMessage's "what".Nope! It IS! See Looper.cpp's: ReadRawFromPort, ReadMessageFromPort, ConvertToMessage methods. A system message with no buffer data IS a valid BMessage.
Ok, so it is used differently. Sometimes it is 'what', sometimes it is for the protocol. This is confusing but perhaps unavoidable. You have to read the implementation to be sure. By using it two ways we fail to establish a convention for others to follow.
In the beginning was PortLink, then came along BSession. When Marc finished BPicture implementation, AreaLink appeared. There was a debate why not to use PortLink over BSession, and I and DW had long talks about that. The fact is, PortLink is message oriented and BSession not streamed, and we need that.
OK, the trade-offs are thus:
You chunk (combine multiple messages) so the server might be able get a second message without waiting on the port queue semaphore. It's optimized for small messages. The (unlikely) non-optimal scenario is a stream of messages larger than 1024 bytes.
You fragment so you can flush at will so don't have to dynamically resize the buffer to avoid overflow.
ATM everything is working just fine with this method in server.
IF, someone tries to unify those will go into serious problems, because of the handler. I mean, if you have a handler that is mainly oriented on PortMessage/PortLink and you send a message with BSession, you will run into BIIIIIG trouble because BSession messages are NOT complete! The other way a BSession handler and sending with PortLink, no problem appears(as you have noticed, in PortLink already there is a method for sending to BSession hander) but a lot of code needs to be modified;
Is the potential BIIIIIG trouble reason to finish the details before using it everywhere?
None, just summarising. Although I might fix the memory management bugs, buffer overflow exploit, and error detection in PortMessage ;-)
I don't see the advantage of this since the server shouldn't execute a command until it has checked all the parameters.
When I wrote the about I mean like:
Read Command: DRAW_LINE Read Parameter: x1 Read Parameter: y1 Read Parameter: x2 Read Parameter: y2 Execute(DRAW_LINE, x1, y1, x2, y2);
:-))) Wrong! While the client side buffer is filling in (BSession's one) app_server is executing drawing instructions. There is a high probability that, by the time the next write_port() is made and the message reaches the server, the previous commands be already executed.
Eh? What do you say about that? Nice, isn't it?
The advantage comes from client-server not from BSession's buffering.
Oh... think if you had PortLink instead of BSession in BWindow/BView? Would you have seen something drawn until BView::Draw() ended? What about if you do a lots of things inside Draw(), how big would have the message been? how long it would have taken for the server to execute instruction found inside? Same is valuable when attaching a large BView tree.
I detect communication problems...I don't know if we're agreeing or disagreeing.
Commands could be write_port'ed one by one for speed or grouped for efficiency.
What I object to is fragmenting a command. Each write_port() should deal with complete messages.
If you want to avoid flicker then the user shouldn't see a BView being drawn command by command. So you would optimize for minimal total drawing time, rather than try and get the first command of many drawn as soon as possible -- assuming you want double buffered/vtrace/vblank drawing as default on the appserver.
Also BSession had all the return error codes removed. I'm unable to create robust software with it. void BSession::ReadData( void* data, int32 size ); void BSession::WriteData(const void* data, int32 size); void BSession::Sync();
Yes, I have added them, then removed. I no longer need them.
a
code = AS_NO_MESSAGE;
ses->ReadInt32(&code)
would tell me if something went wrong. This case... the port has been deleted.
So you have to remember to reset "code" to AS_NO_MESSAGE, and assume that nothing will actually send an int32 with the value of AS_NO_MESSAGE,
and you have to get a reply to know whether or not your send was sucessful. If you don't get a reply, you won't know if it's a problem with your send, or a problem with the server replying.
ses->WriteInt32(COMMAND_1); ses->WriteInt32(PARAMETER_1); ses->WriteInt32(COMMAND_2); ses->ReadInt32(&REPLY_1);
If for some reason WriteInt32(COMMAND_1); failed, then PARAMETER_1 might be interpreted by the server as COMMAND_3 and COMMAND_2 as a parameter.
Then I get REPLY_1 and assume that both COMMAND_1 and COMMAND_2 were sucessfully processed.
char* BSession::ReadString(){
int16 len = 0;
char *str = NULL;ReadData( &len, sizeof(int16));
if (len > 0){
str = (char*)malloc(len+1);
}
return str;
}Good we remembered to initialise len = 0. We ReadData() the length of the string correctly, it is 80.
The third-party application crashes before the string could be written.
We ReadData(str, len) on an invalid port.
The code returns str as non-null.
Our server printf's the unterminated buffer and segfaults.
Or maybe uses some bogus data to corrupt something important.
Why do you need to use BSession? it is private!
Besides the fact I hack on more than one appserver, the Java, Python, and BePascal groups may eventually want to interface directly with the appserver.
No, all datas will be dumped until the next code is recognized.
I know about this... and I had in plan to suffix each instruction with... AS_END_INSTRUCTION.
But some parameter may have the value of AS_END_INSTRUCTION.
In 99.99999% of cases this won't happen. Unless a bad user or program will write to a ServerWindow port. I have discussed this with Michael and he said it is not concerned by security.
Bad users will be happy that we didn't secure the most obvious exploits. Bad third-party programs are a fact of life. Bugs are inevitable. You never know where the problem could cascade to. It's bad design.
As developers of appserver we ourselves will find it hard to debug. We will have a lot of incomplete code and changing protocols. We have to disable BWindow sending X notification eventhough we've implemented it because the appserver isn't ready to deal with message X, and sending it will de-synchronize our stream.
Sorry but it is the only one suited for BWindow/BView <-> app_server communication. It worked perfectly until now and I don't see any problems appearing. Hell... Be used it, and look what a nice graphical interface R5 has.
Do we really need BSession?
Yup!
Considering the trade-offs, I need more persuasion.
Bye, Adi.
- [interfacekit] Re: BSession
- From: Pahtz