[interfacekit] Re: BSession


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/


Other related posts: