2 * Copyright 2001-2011, Haiku.
3 * Distributed under the terms of the MIT License.
6 * Pahtz <pahtz@yahoo.com.au>
8 * Stephan Aßmus <superstippi@gmx.de>
9 * Artur Wyszynski <harakash@gmail.com>
13 /*! Class for low-overhead port-based messaging */
16 #include <LinkReceiver.h>
22 #include <ServerProtocol.h>
25 #include <GradientLinear.h>
26 #include <GradientRadial.h>
27 #include <GradientRadialFocus.h>
28 #include <GradientDiamond.h>
29 #include <GradientConic.h>
31 #include "link_message.h"
33 //#define DEBUG_BPORTLINK
34 #ifdef DEBUG_BPORTLINK
36 # define STRACE(x) printf x
41 //#define TRACE_LINK_RECEIVER_GRADIENTS
42 #ifdef TRACE_LINK_RECEIVER_GRADIENTS
44 # define GTRACE(x) debug_printf x
53 LinkReceiver::LinkReceiver(port_id port
)
55 fReceivePort(port
), fRecvBuffer(NULL
), fRecvPosition(0), fRecvStart(0),
56 fRecvBufferSize(0), fDataSize(0),
57 fReplySize(0), fReadError(B_OK
)
62 LinkReceiver::~LinkReceiver()
69 LinkReceiver::SetPort(port_id port
)
76 LinkReceiver::GetNextMessage(int32
&code
, bigtime_t timeout
)
80 int32 remaining
= fDataSize
- (fRecvStart
+ fReplySize
);
81 STRACE(("info: LinkReceiver GetNextReply() reports %ld bytes remaining in buffer.\n", remaining
));
83 // find the position of the next message header in the buffer
84 message_header
*header
;
86 status_t err
= ReadFromPort(timeout
);
89 remaining
= fDataSize
;
90 header
= (message_header
*)fRecvBuffer
;
92 fRecvStart
+= fReplySize
; // start of the next message
93 fRecvPosition
= fRecvStart
;
94 header
= (message_header
*)(fRecvBuffer
+ fRecvStart
);
97 // check we have a well-formed message
98 if (remaining
< (int32
)sizeof(message_header
)) {
99 // we don't have enough data for a complete header
100 STRACE(("error info: LinkReceiver remaining %ld bytes is less than header size.\n", remaining
));
105 fReplySize
= header
->size
;
106 if (fReplySize
> remaining
|| fReplySize
< (int32
)sizeof(message_header
)) {
107 STRACE(("error info: LinkReceiver message size of %ld bytes smaller than header size.\n", fReplySize
));
113 fRecvPosition
+= sizeof(message_header
);
115 STRACE(("info: LinkReceiver got header %ld [%ld %ld %ld] from port %ld.\n",
116 header
->code
, fReplySize
, header
->code
, header
->flags
, fReceivePort
));
123 LinkReceiver::HasMessages() const
125 return fDataSize
- (fRecvStart
+ fReplySize
) > 0
126 || port_count(fReceivePort
) > 0;
131 LinkReceiver::NeedsReply() const
136 message_header
*header
= (message_header
*)(fRecvBuffer
+ fRecvStart
);
137 return (header
->flags
& kNeedsReply
) != 0;
142 LinkReceiver::Code() const
147 message_header
*header
= (message_header
*)(fRecvBuffer
+ fRecvStart
);
153 LinkReceiver::ResetBuffer()
163 LinkReceiver::AdjustReplyBuffer(bigtime_t timeout
)
165 // Here we take advantage of the compiler's dead-code elimination
166 if (kInitialBufferSize
== kMaxBufferSize
) {
169 if (fRecvBuffer
!= NULL
)
172 fRecvBuffer
= (char *)malloc(kInitialBufferSize
);
173 if (fRecvBuffer
== NULL
)
176 fRecvBufferSize
= kInitialBufferSize
;
178 STRACE(("info: LinkReceiver getting port_buffer_size().\n"));
182 bufferSize
= port_buffer_size_etc(fReceivePort
,
183 timeout
== B_INFINITE_TIMEOUT
? B_RELATIVE_TIMEOUT
: 0,
185 } while (bufferSize
== B_INTERRUPTED
);
187 STRACE(("info: LinkReceiver got port_buffer_size() = %ld.\n", bufferSize
));
190 return (status_t
)bufferSize
;
192 // make sure our receive buffer is large enough
193 if (bufferSize
> fRecvBufferSize
) {
194 if (bufferSize
<= (ssize_t
)kInitialBufferSize
)
195 bufferSize
= (ssize_t
)kInitialBufferSize
;
197 bufferSize
= (bufferSize
+ B_PAGE_SIZE
- 1) & ~(B_PAGE_SIZE
- 1);
199 if (bufferSize
> (ssize_t
)kMaxBufferSize
)
200 return B_ERROR
; // we can't continue
202 STRACE(("info: LinkReceiver setting receive buffersize to %ld.\n", bufferSize
));
203 char *buffer
= (char *)malloc(bufferSize
);
208 fRecvBuffer
= buffer
;
209 fRecvBufferSize
= bufferSize
;
218 LinkReceiver::ReadFromPort(bigtime_t timeout
)
220 // we are here so it means we finished reading the buffer contents
223 status_t err
= AdjustReplyBuffer(timeout
);
230 STRACE(("info: LinkReceiver reading port %ld.\n", fReceivePort
));
232 if (timeout
!= B_INFINITE_TIMEOUT
) {
234 bytesRead
= read_port_etc(fReceivePort
, &code
, fRecvBuffer
,
235 fRecvBufferSize
, B_TIMEOUT
, timeout
);
236 } while (bytesRead
== B_INTERRUPTED
);
239 bytesRead
= read_port(fReceivePort
, &code
, fRecvBuffer
,
241 } while (bytesRead
== B_INTERRUPTED
);
244 STRACE(("info: LinkReceiver read %ld bytes.\n", bytesRead
));
245 if (bytesRead
< B_OK
)
248 // we just ignore incorrect messages, and don't bother our caller
250 if (code
!= kLinkCode
) {
251 STRACE(("wrong port message %lx received.\n", code
));
255 // port read seems to be valid
259 fDataSize
= bytesRead
;
265 LinkReceiver::Read(void *data
, ssize_t passedSize
)
267 // STRACE(("info: LinkReceiver Read()ing %ld bytes...\n", size));
268 ssize_t size
= passedSize
;
270 if (fReadError
< B_OK
)
273 if (data
== NULL
|| size
< 1) {
274 fReadError
= B_BAD_VALUE
;
278 if (fDataSize
== 0 || fReplySize
== 0)
279 return B_NO_INIT
; // need to call GetNextReply() first
281 bool useArea
= false;
282 if ((size_t)size
>= kMaxBufferSize
) {
284 size
= sizeof(area_id
);
287 if (fRecvPosition
+ size
> fRecvStart
+ fReplySize
) {
288 // reading past the end of current message
289 fReadError
= B_BAD_VALUE
;
295 memcpy((void*)&sourceArea
, fRecvBuffer
+ fRecvPosition
, size
);
298 if (get_area_info(sourceArea
, &areaInfo
) < B_OK
)
299 fReadError
= B_BAD_VALUE
;
301 if (fReadError
>= B_OK
) {
302 void* areaAddress
= areaInfo
.address
;
304 if (areaAddress
&& sourceArea
>= B_OK
) {
305 memcpy(data
, areaAddress
, passedSize
);
306 delete_area(sourceArea
);
310 memcpy(data
, fRecvBuffer
+ fRecvPosition
, size
);
312 fRecvPosition
+= size
;
318 LinkReceiver::ReadString(char** _string
, size_t* _length
)
321 status_t status
= Read
<int32
>(&length
);
332 string
= (char *)malloc(length
+ 1);
333 if (string
== NULL
) {
334 status
= B_NO_MEMORY
;
339 status
= Read(string
, length
);
346 // make sure the string is null terminated
347 string
[length
] = '\0';
357 fRecvPosition
-= sizeof(int32
);
358 // rewind the transaction
364 LinkReceiver::ReadString(BString
&string
, size_t* _length
)
367 status_t status
= Read
<int32
>(&length
);
378 char* buffer
= string
.LockBuffer(length
+ 1);
379 if (buffer
== NULL
) {
380 status
= B_NO_MEMORY
;
384 status
= Read(buffer
, length
);
386 string
.UnlockBuffer();
390 // make sure the string is null terminated
391 buffer
[length
] = '\0';
392 string
.UnlockBuffer(length
);
402 fRecvPosition
-= sizeof(int32
);
403 // rewind the transaction
409 LinkReceiver::ReadString(char *buffer
, size_t bufferLength
)
412 status_t status
= Read
<int32
>(&length
);
417 if (length
>= (int32
)bufferLength
) {
418 status
= B_BUFFER_OVERFLOW
;
428 status
= Read(buffer
, length
);
433 // make sure the string is null terminated
434 buffer
[length
] = '\0';
438 fRecvPosition
-= sizeof(int32
);
439 // rewind the transaction
444 LinkReceiver::ReadRegion(BRegion
* region
)
446 status_t status
= Read(®ion
->fCount
, sizeof(int32
));
448 status
= Read(®ion
->fBounds
, sizeof(clipping_rect
));
449 if (status
>= B_OK
) {
450 if (!region
->_SetSize(region
->fCount
))
451 status
= B_NO_MEMORY
;
453 status
= Read(region
->fData
,
454 region
->fCount
* sizeof(clipping_rect
));
464 gradient_for_type(BGradient::Type type
)
467 case BGradient::TYPE_LINEAR
:
468 return new (std::nothrow
) BGradientLinear();
469 case BGradient::TYPE_RADIAL
:
470 return new (std::nothrow
) BGradientRadial();
471 case BGradient::TYPE_RADIAL_FOCUS
:
472 return new (std::nothrow
) BGradientRadialFocus();
473 case BGradient::TYPE_DIAMOND
:
474 return new (std::nothrow
) BGradientDiamond();
475 case BGradient::TYPE_CONIC
:
476 return new (std::nothrow
) BGradientConic();
477 case BGradient::TYPE_NONE
:
478 return new (std::nothrow
) BGradient();
485 LinkReceiver::ReadGradient(BGradient
** _gradient
)
487 GTRACE(("LinkReceiver::ReadGradient\n"));
489 BGradient::Type gradientType
;
491 Read(&gradientType
, sizeof(BGradient::Type
));
492 status_t status
= Read(&colorsCount
, sizeof(int32
));
496 BGradient
* gradient
= gradient_for_type(gradientType
);
500 *_gradient
= gradient
;
502 if (colorsCount
> 0) {
503 BGradient::ColorStop stop
;
504 for (int i
= 0; i
< colorsCount
; i
++) {
505 if ((status
= Read(&stop
, sizeof(BGradient::ColorStop
))) != B_OK
)
507 if (!gradient
->AddColorStop(stop
, i
))
512 switch (gradientType
) {
513 case BGradient::TYPE_LINEAR
:
515 GTRACE(("LinkReceiver::ReadGradient> type == TYPE_LINEAR\n"));
516 BGradientLinear
* linear
= (BGradientLinear
*)gradient
;
519 Read(&start
, sizeof(BPoint
));
520 if ((status
= Read(&end
, sizeof(BPoint
))) != B_OK
)
522 linear
->SetStart(start
);
526 case BGradient::TYPE_RADIAL
:
528 GTRACE(("LinkReceiver::ReadGradient> type == TYPE_RADIAL\n"));
529 BGradientRadial
* radial
= (BGradientRadial
*)gradient
;
532 Read(¢er
, sizeof(BPoint
));
533 if ((status
= Read(&radius
, sizeof(float))) != B_OK
)
535 radial
->SetCenter(center
);
536 radial
->SetRadius(radius
);
539 case BGradient::TYPE_RADIAL_FOCUS
:
541 GTRACE(("LinkReceiver::ReadGradient> type == TYPE_RADIAL_FOCUS\n"));
542 BGradientRadialFocus
* radialFocus
=
543 (BGradientRadialFocus
*)gradient
;
547 Read(¢er
, sizeof(BPoint
));
548 Read(&focal
, sizeof(BPoint
));
549 if ((status
= Read(&radius
, sizeof(float))) != B_OK
)
551 radialFocus
->SetCenter(center
);
552 radialFocus
->SetFocal(focal
);
553 radialFocus
->SetRadius(radius
);
556 case BGradient::TYPE_DIAMOND
:
558 GTRACE(("LinkReceiver::ReadGradient> type == TYPE_DIAMOND\n"));
559 BGradientDiamond
* diamond
= (BGradientDiamond
*)gradient
;
561 if ((status
= Read(¢er
, sizeof(BPoint
))) != B_OK
)
563 diamond
->SetCenter(center
);
566 case BGradient::TYPE_CONIC
:
568 GTRACE(("LinkReceiver::ReadGradient> type == TYPE_CONIC\n"));
569 BGradientConic
* conic
= (BGradientConic
*)gradient
;
572 Read(¢er
, sizeof(BPoint
));
573 if ((status
= Read(&angle
, sizeof(float))) != B_OK
)
575 conic
->SetCenter(center
);
576 conic
->SetAngle(angle
);
579 case BGradient::TYPE_NONE
:
581 GTRACE(("LinkReceiver::ReadGradient> type == TYPE_NONE\n"));
590 } // namespace BPrivate