xref: /haiku/src/kits/app/Message.cpp (revision ddac407426cd3b3d0b4589d7a161b300b3539a2a)
1 /*
2  * Copyright 2005-2009, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include <Message.h>
10 #include <MessageAdapter.h>
11 #include <MessagePrivate.h>
12 #include <MessageUtils.h>
13 
14 #include <DirectMessageTarget.h>
15 #include <MessengerPrivate.h>
16 #include <TokenSpace.h>
17 #include <util/KMessage.h>
18 
19 #include <Application.h>
20 #include <AppMisc.h>
21 #include <BlockCache.h>
22 #include <Entry.h>
23 #include <MessageQueue.h>
24 #include <Messenger.h>
25 #include <Path.h>
26 #include <Point.h>
27 #include <Rect.h>
28 #include <String.h>
29 
30 #include <assert.h>
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "tracing_config.h"
37 	// kernel tracing configuration
38 
39 #define DEBUG_FUNCTION_ENTER	//debug_printf("thread: 0x%x; this: 0x%08x; header: 0x%08x; fields: 0x%08x; data: 0x%08x; line: %04ld; func: %s\n", find_thread(NULL), this, fHeader, fFields, fData, __LINE__, __PRETTY_FUNCTION__);
40 #define DEBUG_FUNCTION_ENTER2	//debug_printf("thread: 0x%x;                                                                             line: %04ld: func: %s\n", find_thread(NULL), __LINE__, __PRETTY_FUNCTION__);
41 
42 
43 #if BMESSAGE_TRACING
44 #	define KTRACE(format...)	ktrace_printf(format)
45 #else
46 #	define KTRACE(format...)
47 #endif
48 
49 
50 const char *B_SPECIFIER_ENTRY = "specifiers";
51 const char *B_PROPERTY_ENTRY = "property";
52 const char *B_PROPERTY_NAME_ENTRY = "name";
53 
54 
55 static status_t	handle_reply(port_id replyPort, int32 *pCode, bigtime_t timeout,
56 	BMessage *reply);
57 
58 extern "C" {
59 	// private os function to set the owning team of an area
60 	status_t _kern_transfer_area(area_id area, void **_address,
61 		uint32 addressSpec, team_id target);
62 }
63 
64 
65 BBlockCache *BMessage::sMsgCache = NULL;
66 port_id BMessage::sReplyPorts[sNumReplyPorts];
67 long BMessage::sReplyPortInUse[sNumReplyPorts];
68 
69 
70 template<typename Type> static uint8 *
71 print_to_stream_type(uint8* pointer)
72 {
73 	Type *item = (Type *)pointer;
74 	item->PrintToStream();
75 	return (uint8 *)(item+1);
76 }
77 
78 
79 template<typename Type> static uint8 *
80 print_type(const char* format, uint8* pointer)
81 {
82 	Type *item = (Type *)pointer;
83 	printf(format, *item, *item);
84 	return (uint8 *)(item+1);
85 }
86 
87 
88 static status_t
89 handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout,
90 	BMessage *reply)
91 {
92 	DEBUG_FUNCTION_ENTER2;
93 	ssize_t size;
94 	do {
95 		size = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout);
96 	} while (size == B_INTERRUPTED);
97 
98 	if (size < B_OK)
99 		return size;
100 
101 	status_t result;
102 	char *buffer = (char *)malloc(size);
103 	if (buffer == NULL)
104 		return B_NO_MEMORY;
105 
106 	do {
107 		result = read_port(replyPort, _code, buffer, size);
108 	} while (result == B_INTERRUPTED);
109 
110 	if (result < B_OK || *_code != kPortMessageCode) {
111 		free(buffer);
112 		return result < B_OK ? result : B_ERROR;
113 	}
114 
115 	result = reply->Unflatten(buffer);
116 	free(buffer);
117 	return result;
118 }
119 
120 
121 //	#pragma mark -
122 
123 
124 BMessage::BMessage()
125 {
126 	DEBUG_FUNCTION_ENTER;
127 	_InitCommon(true);
128 }
129 
130 
131 BMessage::BMessage(BMessage *other)
132 {
133 	DEBUG_FUNCTION_ENTER;
134 	_InitCommon(false);
135 	*this = *other;
136 }
137 
138 
139 BMessage::BMessage(uint32 _what)
140 {
141 	DEBUG_FUNCTION_ENTER;
142 	_InitCommon(true);
143 	fHeader->what = what = _what;
144 }
145 
146 
147 BMessage::BMessage(const BMessage &other)
148 {
149 	DEBUG_FUNCTION_ENTER;
150 	_InitCommon(false);
151 	*this = other;
152 }
153 
154 
155 BMessage::~BMessage()
156 {
157 	DEBUG_FUNCTION_ENTER;
158 	_Clear();
159 }
160 
161 
162 BMessage &
163 BMessage::operator=(const BMessage &other)
164 {
165 	DEBUG_FUNCTION_ENTER;
166 
167     if (this == &other)
168         return *this;
169 
170 	_Clear();
171 
172 	fHeader = (message_header *)malloc(sizeof(message_header));
173 	memcpy(fHeader, other.fHeader, sizeof(message_header));
174 
175 	// Clear some header flags inherited from the original message that don't
176 	// apply to the clone.
177 	fHeader->flags &= ~(MESSAGE_FLAG_REPLY_REQUIRED | MESSAGE_FLAG_REPLY_DONE
178 		| MESSAGE_FLAG_IS_REPLY | MESSAGE_FLAG_WAS_DELIVERED
179 		| MESSAGE_FLAG_WAS_DROPPED | MESSAGE_FLAG_PASS_BY_AREA);
180 	// Note, that BeOS R5 seems to keep the reply info.
181 
182 	if (fHeader->fields_size > 0) {
183 		fFields = (field_header *)malloc(fHeader->fields_size);
184 		memcpy(fFields, other.fFields, fHeader->fields_size);
185 	}
186 
187 	if (fHeader->data_size > 0) {
188 		fData = (uint8 *)malloc(fHeader->data_size);
189 		memcpy(fData, other.fData, fHeader->data_size);
190 	}
191 
192 	fHeader->message_area = -1;
193 	fHeader->fields_available = 0;
194 	fHeader->data_available = 0;
195 	fHeader->what = what = other.what;
196 
197 	return *this;
198 }
199 
200 
201 void *
202 BMessage::operator new(size_t size)
203 {
204 	DEBUG_FUNCTION_ENTER2;
205 	void *pointer = sMsgCache->Get(size);
206 	return pointer;
207 }
208 
209 
210 void *
211 BMessage::operator new(size_t, void *pointer)
212 {
213 	DEBUG_FUNCTION_ENTER2;
214 	return pointer;
215 }
216 
217 
218 void
219 BMessage::operator delete(void *pointer, size_t size)
220 {
221 	DEBUG_FUNCTION_ENTER2;
222 	sMsgCache->Save(pointer, size);
223 }
224 
225 
226 bool
227 BMessage::HasSameData(const BMessage &other, bool ignoreFieldOrder,
228 	bool deep) const
229 {
230 	if (this == &other)
231 		return true;
232 
233 	if (fHeader->field_count != other.fHeader->field_count)
234 		return false;
235 
236 	for (int32 i = 0; i < fHeader->field_count; i++) {
237 		field_header *field = &fFields[i];
238 		field_header *otherField = NULL;
239 
240 		const char *name = (const char *)fData + field->offset;
241 		if (ignoreFieldOrder) {
242 			if (other._FindField(name, B_ANY_TYPE, &otherField) != B_OK)
243 				return false;
244 		} else {
245 			otherField = &other.fFields[i];
246 			if (otherField->name_length != field->name_length)
247 				return false;
248 
249 			const char *otherName = (const char *)other.fData
250 				+ otherField->offset;
251 			if (strncmp(name, otherName, field->name_length) != 0)
252 				return false;
253 		}
254 
255 		if (otherField->type != field->type || otherField->count != field->count)
256 			return false;
257 
258 		uint8 *data = fData + field->offset + field->name_length;
259 		uint8 *otherData = other.fData + otherField->offset
260 			+ otherField->name_length;
261 
262 		bool needsMemCompare = true;
263 		if (deep && field->type == B_MESSAGE_TYPE) {
264 			BMessage message, otherMessage;
265 			if (message.Unflatten((const char *)data) == B_OK
266 				&& otherMessage.Unflatten((const char *)otherData) == B_OK) {
267 				if (!message.HasSameData(ignoreFieldOrder, deep))
268 					return false;
269 				needsMemCompare = false;
270 			}
271 		}
272 
273 		if (needsMemCompare) {
274 			if (otherField->data_size != field->data_size)
275 				return false;
276 			if (memcmp(data, otherData, field->data_size) != 0)
277 				return false;
278 		}
279 	}
280 
281 	return true;
282 }
283 
284 
285 status_t
286 BMessage::_InitCommon(bool initHeader)
287 {
288 	DEBUG_FUNCTION_ENTER;
289 	what = 0;
290 
291 	fHeader = NULL;
292 	fFields = NULL;
293 	fData = NULL;
294 
295 	fOriginal = NULL;
296 	fQueueLink = NULL;
297 
298 	if (initHeader)
299 		return _InitHeader();
300 
301 	fHeader = NULL;
302 	return B_OK;
303 }
304 
305 
306 status_t
307 BMessage::_InitHeader()
308 {
309 	DEBUG_FUNCTION_ENTER;
310 	fHeader = (message_header *)malloc(sizeof(message_header));
311 	memset(fHeader, 0, sizeof(message_header) - sizeof(fHeader->hash_table));
312 
313 	fHeader->format = MESSAGE_FORMAT_HAIKU;
314 	fHeader->flags = MESSAGE_FLAG_VALID;
315 	fHeader->what = what;
316 	fHeader->current_specifier = -1;
317 	fHeader->message_area = -1;
318 
319 	fHeader->target = B_NULL_TOKEN;
320 	fHeader->reply_target = B_NULL_TOKEN;
321 	fHeader->reply_port = -1;
322 	fHeader->reply_team = -1;
323 
324 	// initializing the hash table to -1 because 0 is a valid index
325 	fHeader->hash_table_size = MESSAGE_BODY_HASH_TABLE_SIZE;
326 	memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
327 	return B_OK;
328 }
329 
330 
331 status_t
332 BMessage::_Clear()
333 {
334 	DEBUG_FUNCTION_ENTER;
335 	if (fHeader) {
336 		// We're going to destroy all information of this message. If there's
337 		// still someone waiting for a reply to this message, we have to send
338 		// one now.
339 		if (IsSourceWaiting())
340 			SendReply(B_NO_REPLY);
341 
342 		if (fHeader->message_area >= 0)
343 			_Dereference();
344 
345 		free(fHeader);
346 		fHeader = NULL;
347 	}
348 
349 	free(fFields);
350 	fFields = NULL;
351 	free(fData);
352 	fData = NULL;
353 
354 	delete fOriginal;
355 	fOriginal = NULL;
356 
357 	return B_OK;
358 }
359 
360 
361 status_t
362 BMessage::GetInfo(type_code typeRequested, int32 index, char **nameFound,
363 	type_code *typeFound, int32 *countFound) const
364 {
365 	DEBUG_FUNCTION_ENTER;
366 	if (typeRequested == B_ANY_TYPE) {
367 		if (index >= fHeader->field_count)
368 			return B_BAD_INDEX;
369 
370 		if (nameFound)
371 			*nameFound = (char *)fData + fFields[index].offset;
372 		if (typeFound)
373 			*typeFound = fFields[index].type;
374 		if (countFound)
375 			*countFound = fFields[index].count;
376 		return B_OK;
377 	}
378 
379 	int32 counter = -1;
380 	field_header *field = fFields;
381 	for (int32 i = 0; i < fHeader->field_count; i++, field++) {
382 		if (field->type == typeRequested)
383 			counter++;
384 
385 		if (counter == index) {
386 			if (nameFound)
387 				*nameFound = (char *)fData + field->offset;
388 			if (typeFound)
389 				*typeFound = field->type;
390 			if (countFound)
391 				*countFound = field->count;
392 			return B_OK;
393 		}
394 	}
395 
396 	if (counter == -1)
397 		return B_BAD_TYPE;
398 
399 	return B_BAD_INDEX;
400 }
401 
402 
403 status_t
404 BMessage::GetInfo(const char *name, type_code *typeFound, int32 *countFound)
405 	const
406 {
407 	DEBUG_FUNCTION_ENTER;
408 	if (countFound)
409 		*countFound = 0;
410 
411 	field_header *field = NULL;
412 	status_t result = _FindField(name, B_ANY_TYPE, &field);
413 	if (result < B_OK || !field)
414 		return result;
415 
416 	if (typeFound)
417 		*typeFound = field->type;
418 	if (countFound)
419 		*countFound = field->count;
420 
421 	return B_OK;
422 }
423 
424 
425 status_t
426 BMessage::GetInfo(const char *name, type_code *typeFound, bool *fixedSize)
427 	const
428 {
429 	DEBUG_FUNCTION_ENTER;
430 	field_header *field = NULL;
431 	status_t result = _FindField(name, B_ANY_TYPE, &field);
432 	if (result < B_OK || !field)
433 		return result;
434 
435 	if (typeFound)
436 		*typeFound = field->type;
437 	if (fixedSize)
438 		*fixedSize = field->flags & FIELD_FLAG_FIXED_SIZE;
439 
440 	return B_OK;
441 }
442 
443 
444 int32
445 BMessage::CountNames(type_code type) const
446 {
447 	DEBUG_FUNCTION_ENTER;
448 	if (type == B_ANY_TYPE)
449 		return fHeader->field_count;
450 
451 	int32 count = 0;
452 	field_header *field = fFields;
453 	for (int32 i = 0; i < fHeader->field_count; i++, field++) {
454 		if (field->type == type)
455 			count++;
456 	}
457 
458 	return count;
459 }
460 
461 
462 bool
463 BMessage::IsEmpty() const
464 {
465 	DEBUG_FUNCTION_ENTER;
466 	return fHeader->field_count == 0;
467 }
468 
469 
470 bool
471 BMessage::IsSystem() const
472 {
473 	DEBUG_FUNCTION_ENTER;
474 	char a = char(what >> 24);
475 	char b = char(what >> 16);
476 	char c = char(what >> 8);
477 	char d = char(what);
478 
479 	// The BeBook says:
480 	//		... we've adopted a strict convention for assigning values to all
481 	//		Be-defined constants.  The value assigned will always be formed by
482 	//		combining four characters into a multicharacter constant, with the
483 	//		characters limited to uppercase letters and the underbar
484 	// Between that and what's in AppDefs.h, this algo seems like a safe bet:
485 	if (a == '_' && isupper(b) && isupper(c) && isupper(d))
486 		return true;
487 
488 	return false;
489 }
490 
491 
492 bool
493 BMessage::IsReply() const
494 {
495 	DEBUG_FUNCTION_ENTER;
496 	return fHeader->flags & MESSAGE_FLAG_IS_REPLY;
497 }
498 
499 
500 void
501 BMessage::PrintToStream() const
502 {
503 	_PrintToStream("");
504 	printf("}\n");
505 }
506 
507 
508 void
509 BMessage::_PrintToStream(const char* indent) const
510 {
511 	DEBUG_FUNCTION_ENTER;
512 
513 	int32 value = B_BENDIAN_TO_HOST_INT32(what);
514 	printf("BMessage(");
515 	if (isprint(*(char *)&value)) {
516 		printf("'%.4s'", (char *)&value);
517 	} else
518 		printf("0x%lx", what);
519 	printf(") {\n");
520 
521 	field_header *field = fFields;
522 	for (int32 i = 0; i < fHeader->field_count; i++, field++) {
523 		value = B_BENDIAN_TO_HOST_INT32(field->type);
524 		ssize_t size = 0;
525 		if ((field->flags & FIELD_FLAG_FIXED_SIZE) && field->count > 0)
526 			size = field->data_size / field->count;
527 
528 		uint8 *pointer = fData + field->offset + field->name_length;
529 		for (int32 j = 0; j < field->count; j++) {
530 			if (field->count == 1) {
531 				printf("%s        %s = ", indent,
532 					(char *)(fData + field->offset));
533 			} else {
534 				printf("%s        %s[%ld] = ", indent,
535 					(char *)(fData + field->offset), j);
536 			}
537 
538 			switch (field->type) {
539 				case B_RECT_TYPE:
540 					pointer = print_to_stream_type<BRect>(pointer);
541 					break;
542 
543 				case B_POINT_TYPE:
544 					pointer = print_to_stream_type<BPoint>(pointer);
545 					break;
546 
547 				case B_STRING_TYPE:	{
548 					ssize_t size = *(ssize_t *)pointer;
549 					pointer += sizeof(ssize_t);
550 					printf("string(\"%s\", %ld bytes)\n", (char *)pointer, size);
551 					pointer += size;
552 					break;
553 				}
554 
555 				case B_INT8_TYPE:
556 					pointer = print_type<int8>("int8(0x%hx or %d or \'%.1s\')\n", pointer);
557 					break;
558 
559 				case B_INT16_TYPE:
560 					pointer = print_type<int16>("int16 (0x%x or %d)\n", pointer);
561 					break;
562 
563 				case B_INT32_TYPE:
564 					pointer = print_type<int32>("int32(0x%lx or %ld)\n", pointer);
565 					break;
566 
567 				case B_INT64_TYPE:
568 					pointer = print_type<int64>("int64(0x%Lx or %Ld)\n", pointer);
569 					break;
570 
571 				case B_BOOL_TYPE:
572 					printf("bool(%s)\n", *((bool *)pointer)!= 0 ? "true" : "false");
573 					pointer += sizeof(bool);
574 					break;
575 
576 				case B_FLOAT_TYPE:
577 					pointer = print_type<float>("float(%.4f)\n", pointer);
578 					break;
579 
580 				case B_DOUBLE_TYPE:
581 					pointer = print_type<double>("double(%.8f)\n", pointer);
582 					break;
583 
584 				case B_REF_TYPE: {
585 					ssize_t size = *(ssize_t *)pointer;
586 					pointer += sizeof(ssize_t);
587 					entry_ref ref;
588 					BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
589 
590 					printf("entry_ref(device=%ld, directory=%lld, name=\"%s\", ",
591 							ref.device, ref.directory, ref.name);
592 
593 					BPath path(&ref);
594 					printf("path=\"%s\")\n", path.Path());
595 					pointer += size;
596 					break;
597 				}
598 
599 				case B_MESSAGE_TYPE:
600 				{
601 					char buffer[1024];
602 					sprintf(buffer, "%s        ", indent);
603 
604 					BMessage message;
605 					const ssize_t size = *(const ssize_t *)pointer;
606 					pointer += sizeof(ssize_t);
607 					if (message.Unflatten((const char *)pointer)!=B_OK) {
608 						fprintf(stderr, "couldn't unflatten item %ld\n", i);
609 						break;
610 					}
611 					message._PrintToStream(buffer);
612 					printf("%s        }\n", indent);
613 					pointer += size;
614 					break;
615 				}
616 
617 				default: {
618 					printf("(type = '%.4s')(size = %ld)\n", (char *)&value, size);
619 				}
620 			}
621 		}
622 	}
623 }
624 
625 
626 status_t
627 BMessage::Rename(const char *oldEntry, const char *newEntry)
628 {
629 	DEBUG_FUNCTION_ENTER;
630 	if (!oldEntry || !newEntry)
631 		return B_BAD_VALUE;
632 
633 	if (fHeader->message_area >= 0)
634 		_CopyForWrite();
635 
636 	uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
637 	int32 *nextField = &fHeader->hash_table[hash];
638 
639 	while (*nextField >= 0) {
640 		field_header *field = &fFields[*nextField];
641 
642 		if (strncmp((const char *)(fData + field->offset), oldEntry,
643 			field->name_length) == 0) {
644 			// nextField points to the field for oldEntry, save it and unlink
645 			int32 index = *nextField;
646 			*nextField = field->next_field;
647 			field->next_field = -1;
648 
649 			hash = _HashName(newEntry) % fHeader->hash_table_size;
650 			nextField = &fHeader->hash_table[hash];
651 			while (*nextField >= 0)
652 				nextField = &fFields[*nextField].next_field;
653 			*nextField = index;
654 
655 			int32 newLength = strlen(newEntry) + 1;
656 			status_t result = _ResizeData(field->offset + 1,
657 				newLength - field->name_length);
658 			if (result < B_OK)
659 				return result;
660 
661 			memcpy(fData + field->offset, newEntry, newLength);
662 			field->name_length = newLength;
663 			return B_OK;
664 		}
665 
666 		nextField = &field->next_field;
667 	}
668 
669 	return B_NAME_NOT_FOUND;
670 }
671 
672 
673 bool
674 BMessage::WasDelivered() const
675 {
676 	DEBUG_FUNCTION_ENTER;
677 	return fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED;
678 }
679 
680 
681 bool
682 BMessage::IsSourceWaiting() const
683 {
684 	DEBUG_FUNCTION_ENTER;
685 	return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED)
686 		&& !(fHeader->flags & MESSAGE_FLAG_REPLY_DONE);
687 }
688 
689 
690 bool
691 BMessage::IsSourceRemote() const
692 {
693 	DEBUG_FUNCTION_ENTER;
694 	return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED)
695 		&& (fHeader->reply_team != BPrivate::current_team());
696 }
697 
698 
699 BMessenger
700 BMessage::ReturnAddress() const
701 {
702 	DEBUG_FUNCTION_ENTER;
703 	if (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) {
704 		BMessenger messenger;
705 		BMessenger::Private(messenger).SetTo(fHeader->reply_team,
706 			fHeader->reply_port, fHeader->reply_target);
707 		return messenger;
708 	}
709 
710 	return BMessenger();
711 }
712 
713 
714 const BMessage *
715 BMessage::Previous() const
716 {
717 	DEBUG_FUNCTION_ENTER;
718 	/* ToDo: test if the "_previous_" field is used in R5 */
719 	if (!fOriginal) {
720 		fOriginal = new BMessage();
721 
722 		if (FindMessage("_previous_", fOriginal) != B_OK) {
723 			delete fOriginal;
724 			fOriginal = NULL;
725 		}
726 	}
727 
728 	return fOriginal;
729 }
730 
731 
732 bool
733 BMessage::WasDropped() const
734 {
735 	DEBUG_FUNCTION_ENTER;
736 	return fHeader->flags & MESSAGE_FLAG_WAS_DROPPED;
737 }
738 
739 
740 BPoint
741 BMessage::DropPoint(BPoint *offset) const
742 {
743 	DEBUG_FUNCTION_ENTER;
744 	if (offset)
745 		*offset = FindPoint("_drop_offset_");
746 
747 	return FindPoint("_drop_point_");
748 }
749 
750 
751 status_t
752 BMessage::SendReply(uint32 command, BHandler *replyTo)
753 {
754 	DEBUG_FUNCTION_ENTER;
755 	BMessage message(command);
756 	return SendReply(&message, replyTo);
757 }
758 
759 
760 status_t
761 BMessage::SendReply(BMessage *reply, BHandler *replyTo, bigtime_t timeout)
762 {
763 	DEBUG_FUNCTION_ENTER;
764 	BMessenger messenger(replyTo);
765 	return SendReply(reply, messenger, timeout);
766 }
767 
768 
769 status_t
770 BMessage::SendReply(BMessage *reply, BMessenger replyTo, bigtime_t timeout)
771 {
772 	DEBUG_FUNCTION_ENTER;
773 	BMessenger messenger;
774 	BMessenger::Private messengerPrivate(messenger);
775 	messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
776 		fHeader->reply_target);
777 
778 	if (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) {
779 		if (fHeader->flags & MESSAGE_FLAG_REPLY_DONE)
780 			return B_DUPLICATE_REPLY;
781 
782 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
783 		reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
784 		status_t result = messenger.SendMessage(reply, replyTo, timeout);
785 		reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
786 
787 		if (result != B_OK) {
788 			if (set_port_owner(messengerPrivate.Port(),
789 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
790 				delete_port(messengerPrivate.Port());
791 			}
792 		}
793 
794 		return result;
795 	}
796 
797 	// no reply required
798 	if (!(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED))
799 		return B_BAD_REPLY;
800 
801 	reply->AddMessage("_previous_", this);
802 	reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
803 	status_t result = messenger.SendMessage(reply, replyTo, timeout);
804 	reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
805 	reply->RemoveName("_previous_");
806 	return result;
807 }
808 
809 
810 status_t
811 BMessage::SendReply(uint32 command, BMessage *replyToReply)
812 {
813 	DEBUG_FUNCTION_ENTER;
814 	BMessage message(command);
815 	return SendReply(&message, replyToReply);
816 }
817 
818 
819 status_t
820 BMessage::SendReply(BMessage *reply, BMessage *replyToReply,
821 	bigtime_t sendTimeout, bigtime_t replyTimeout)
822 {
823 	DEBUG_FUNCTION_ENTER;
824 	BMessenger messenger;
825 	BMessenger::Private messengerPrivate(messenger);
826 	messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
827 		fHeader->reply_target);
828 
829 	if (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) {
830 		if (fHeader->flags & MESSAGE_FLAG_REPLY_DONE)
831 			return B_DUPLICATE_REPLY;
832 
833 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
834 		reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
835 		status_t result = messenger.SendMessage(reply, replyToReply,
836 			sendTimeout, replyTimeout);
837 		reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
838 
839 		if (result != B_OK) {
840 			if (set_port_owner(messengerPrivate.Port(),
841 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
842 				delete_port(messengerPrivate.Port());
843 			}
844 		}
845 
846 		return result;
847 	}
848 
849 	// no reply required
850 	if (!(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED))
851 		return B_BAD_REPLY;
852 
853 	reply->AddMessage("_previous_", this);
854 	reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
855 	status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout,
856 		replyTimeout);
857 	reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
858 	reply->RemoveName("_previous_");
859 	return result;
860 }
861 
862 
863 ssize_t
864 BMessage::FlattenedSize() const
865 {
866 	DEBUG_FUNCTION_ENTER;
867 	return BPrivate::MessageAdapter::FlattenedSize(MESSAGE_FORMAT_R5, this);
868 }
869 
870 
871 status_t
872 BMessage::Flatten(char *buffer, ssize_t size) const
873 {
874 	DEBUG_FUNCTION_ENTER;
875 	return BPrivate::MessageAdapter::Flatten(MESSAGE_FORMAT_R5, this, buffer,
876 		&size);
877 }
878 
879 
880 status_t
881 BMessage::Flatten(BDataIO *stream, ssize_t *size) const
882 {
883 	DEBUG_FUNCTION_ENTER;
884 	return BPrivate::MessageAdapter::Flatten(MESSAGE_FORMAT_R5, this, stream,
885 		size);
886 }
887 
888 
889 ssize_t
890 BMessage::_NativeFlattenedSize() const
891 {
892 	DEBUG_FUNCTION_ENTER;
893 	return sizeof(message_header) + fHeader->fields_size + fHeader->data_size;
894 }
895 
896 
897 status_t
898 BMessage::_NativeFlatten(char *buffer, ssize_t size) const
899 {
900 	DEBUG_FUNCTION_ENTER;
901 	if (!buffer)
902 		return B_BAD_VALUE;
903 
904 	if (!fHeader)
905 		return B_NO_INIT;
906 
907 	/* we have to sync the what code as it is a public member */
908 	fHeader->what = what;
909 
910 	memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
911 	buffer += sizeof(message_header);
912 	size -= sizeof(message_header);
913 
914 	memcpy(buffer, fFields, min_c(fHeader->fields_size, size));
915 	buffer += fHeader->fields_size;
916 	size -= fHeader->fields_size;
917 
918 	memcpy(buffer, fData, min_c(fHeader->data_size, size));
919 	if (size >= fHeader->data_size)
920 		return B_OK;
921 
922 	return B_NO_MEMORY;
923 }
924 
925 
926 status_t
927 BMessage::_NativeFlatten(BDataIO *stream, ssize_t *size) const
928 {
929 	DEBUG_FUNCTION_ENTER;
930 	if (!stream)
931 		return B_BAD_VALUE;
932 
933 	if (!fHeader)
934 		return B_NO_INIT;
935 
936 	/* we have to sync the what code as it is a public member */
937 	fHeader->what = what;
938 
939 	ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
940 	if (result1 != sizeof(message_header))
941 		return (result1 >= 0 ? B_ERROR : result1);
942 
943 	ssize_t result2 = 0;
944 	if (fHeader->fields_size > 0) {
945 		result2 = stream->Write(fFields, fHeader->fields_size);
946 		if (result2 != fHeader->fields_size)
947 			return (result2 >= 0 ? B_ERROR : result2);
948 	}
949 
950 	ssize_t result3 = 0;
951 	if (fHeader->data_size > 0) {
952 		result3 = stream->Write(fData, fHeader->data_size);
953 		if (result3 != fHeader->data_size)
954 			return (result3 >= 0 ? B_ERROR : result3);
955 	}
956 
957 	if (size)
958 		*size = result1 + result2 + result3;
959 
960 	return B_OK;
961 }
962 
963 
964 /*	The concept of message sending by area:
965 
966 	The traditional way of sending a message is to send it by flattening it to
967 	a buffer, pushing it through a port, reading it into the outputbuffer and
968 	unflattening it from there (copying the data again). While this works ok
969 	for small messages it does not make any sense for larger ones and may even
970 	hit some port capacity limit.
971 	Often in the life of a BMessage, it will be sent to someone. Almost as
972 	often the one receiving the message will not need to change the message
973 	in any way, but uses it "read only" to get information from it. This means
974 	that all that copying is pretty pointless in the first place since we
975 	could simply pass the original buffers on.
976 	It's obviously not exactly as simple as this, since we cannot just use the
977 	memory of one application in another - but we can share areas with
978 	eachother.
979 	Therefore instead of flattening into a buffer, we copy the message data
980 	into an area, put this information into the message header and only push
981 	this through the port. The receiving looper then builds a BMessage from
982 	the header, that only references the data in the area (not copying it),
983 	allowing read only access to it.
984 	Only if write access is necessary the message will be copyed from the area
985 	to its own buffers (like in the unflatten step before).
986 	The double copying is reduced to a single copy in most cases and we safe
987 	the slower route of moving the data through a port.
988 	Additionally we save us the reference counting with the use of areas that
989 	are reference counted internally. So we don't have to worry about leaving
990 	an area behind or deleting one that is still in use.
991 */
992 
993 status_t
994 BMessage::_FlattenToArea(message_header **_header) const
995 {
996 	DEBUG_FUNCTION_ENTER;
997 	message_header *header = (message_header *)malloc(sizeof(message_header));
998 	if (header == NULL)
999 		return B_NO_MEMORY;
1000 
1001 	memcpy(header, fHeader, sizeof(message_header));
1002 
1003 	header->what = what;
1004 	header->fields_available = 0;
1005 	header->data_available = 0;
1006 	header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
1007 	*_header = header;
1008 
1009 	if (header->message_area >= 0)
1010 		return B_OK;
1011 
1012 	if (header->fields_size == 0 && header->data_size == 0)
1013 		return B_OK;
1014 
1015 	uint8 *address = NULL;
1016 	ssize_t size = header->fields_size + header->data_size;
1017 	size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
1018 	area_id area = create_area("BMessage data", (void **)&address,
1019 		B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1020 
1021 	if (area < B_OK) {
1022 		free(header);
1023 		*_header = NULL;
1024 		return area;
1025 	}
1026 
1027 	if (header->fields_size > 0) {
1028 		memcpy(address, fFields, header->fields_size);
1029 		header->fields_checksum = BPrivate::CalculateChecksum((uint8 *)address, header->fields_size);
1030 		address += header->fields_size;
1031 	}
1032 
1033 	if (header->data_size > 0) {
1034 		memcpy(address, fData, header->data_size);
1035 		header->data_checksum = BPrivate::CalculateChecksum((uint8 *)address, header->data_size);
1036 	}
1037 
1038 	header->message_area = area;
1039 	return B_OK;
1040 }
1041 
1042 
1043 status_t
1044 BMessage::_Reference(message_header *header)
1045 {
1046 	DEBUG_FUNCTION_ENTER;
1047 	fHeader = header;
1048 	fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA;
1049 
1050 	/* if there is no data at all we don't need the area */
1051 	if (fHeader->fields_size == 0 && header->data_size == 0)
1052 		return B_OK;
1053 
1054 	area_info areaInfo;
1055 	status_t result = get_area_info(fHeader->message_area, &areaInfo);
1056 	if (result < B_OK)
1057 		return result;
1058 
1059 	uint8 *address = NULL;
1060 	thread_info threadInfo;
1061 	get_thread_info(find_thread(NULL), &threadInfo);
1062 	if (areaInfo.team != threadInfo.team) {
1063 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
1064 		// we are accessing a message from a port not owned by us
1065 		area_id transfered = _kern_transfer_area(fHeader->message_area,
1066 			(void **)&address, B_ANY_ADDRESS, threadInfo.team);
1067 		if (transfered < 0) {
1068 			debug_printf("BMessage: failed to transfer area into current team\n");
1069 			return transfered;
1070 		}
1071 
1072 		fHeader->message_area = transfered;
1073 #endif
1074 	} else
1075 		address = (uint8 *)areaInfo.address;
1076 
1077 	fFields = (field_header *)address;
1078 	address += fHeader->fields_size;
1079 	fData = address;
1080 
1081 	// ToDo: once we fully trust this mechanism we might want to remove this
1082 	if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
1083 		|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
1084 		debug_printf("BMessage: checksum mismatch in message passed by area!\n");
1085 		_Clear();
1086 		_InitHeader();
1087 		return B_BAD_VALUE;
1088 	}
1089 
1090 	return B_OK;
1091 }
1092 
1093 
1094 status_t
1095 BMessage::_Dereference()
1096 {
1097 	DEBUG_FUNCTION_ENTER;
1098 	delete_area(fHeader->message_area);
1099 	fHeader->message_area = -1;
1100 	fFields = NULL;
1101 	fData = NULL;
1102 	return B_OK;
1103 }
1104 
1105 
1106 status_t
1107 BMessage::_CopyForWrite()
1108 {
1109 	DEBUG_FUNCTION_ENTER;
1110 
1111 	field_header *newFields = NULL;
1112 	uint8 *newData = NULL;
1113 
1114 	if (fHeader->fields_size > 0) {
1115 		newFields = (field_header *)malloc(fHeader->fields_size);
1116 		if (newFields == NULL)
1117 			return B_NO_MEMORY;
1118 
1119 		memcpy(newFields, fFields, fHeader->fields_size);
1120 	}
1121 
1122 	if (fHeader->data_size > 0) {
1123 		newData = (uint8 *)malloc(fHeader->data_size);
1124 		if (newData == NULL) {
1125 			free(newFields);
1126 			return B_NO_MEMORY;
1127 		}
1128 
1129 		memcpy(newData, fData, fHeader->data_size);
1130 	}
1131 
1132 	_Dereference();
1133 
1134 	fHeader->fields_available = 0;
1135 	fHeader->data_available = 0;
1136 
1137 	fFields = newFields;
1138 	fData = newData;
1139 	return B_OK;
1140 }
1141 
1142 
1143 status_t
1144 BMessage::Unflatten(const char *flatBuffer)
1145 {
1146 	DEBUG_FUNCTION_ENTER;
1147 	if (!flatBuffer)
1148 		return B_BAD_VALUE;
1149 
1150 	uint32 format = *(uint32 *)flatBuffer;
1151 	if (format != MESSAGE_FORMAT_HAIKU)
1152 		return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
1153 
1154 	// native message unflattening
1155 
1156 	_Clear();
1157 
1158 	fHeader = (message_header *)malloc(sizeof(message_header));
1159 	if (!fHeader)
1160 		return B_NO_MEMORY;
1161 
1162 	memcpy(fHeader, flatBuffer, sizeof(message_header));
1163 	flatBuffer += sizeof(message_header);
1164 
1165 	if (fHeader->format != MESSAGE_FORMAT_HAIKU
1166 		|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
1167 		free(fHeader);
1168 		fHeader = NULL;
1169 		_InitHeader();
1170 		return B_BAD_VALUE;
1171 	}
1172 
1173 	fHeader->fields_available = 0;
1174 	fHeader->data_available = 0;
1175 	what = fHeader->what;
1176 
1177 	if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) {
1178 		status_t result = _Reference(fHeader);
1179 		if (result < B_OK)
1180 			return result;
1181 	} else {
1182 		fHeader->message_area = -1;
1183 
1184 		if (fHeader->fields_size > 0) {
1185 			fFields = (field_header *)malloc(fHeader->fields_size);
1186 			if (!fFields)
1187 				return B_NO_MEMORY;
1188 
1189 			memcpy(fFields, flatBuffer, fHeader->fields_size);
1190 			flatBuffer += fHeader->fields_size;
1191 		}
1192 
1193 		if (fHeader->data_size > 0) {
1194 			fData = (uint8 *)malloc(fHeader->data_size);
1195 			if (!fData) {
1196 				free(fFields);
1197 				fFields = NULL;
1198 				return B_NO_MEMORY;
1199 			}
1200 
1201 			memcpy(fData, flatBuffer, fHeader->data_size);
1202 		}
1203 	}
1204 
1205 	return B_OK;
1206 }
1207 
1208 
1209 status_t
1210 BMessage::Unflatten(BDataIO *stream)
1211 {
1212 	DEBUG_FUNCTION_ENTER;
1213 	if (!stream)
1214 		return B_BAD_VALUE;
1215 
1216 	uint32 format = 0;
1217 	stream->Read(&format, sizeof(uint32));
1218 	if (format != MESSAGE_FORMAT_HAIKU)
1219 		return BPrivate::MessageAdapter::Unflatten(format, this, stream);
1220 
1221 	// native message unflattening
1222 
1223 	_Clear();
1224 
1225 	fHeader = (message_header *)malloc(sizeof(message_header));
1226 	if (!fHeader)
1227 		return B_NO_MEMORY;
1228 
1229 	fHeader->format = format;
1230 	uint8 *header = (uint8 *)fHeader;
1231 	ssize_t result = stream->Read(header + sizeof(uint32),
1232 		sizeof(message_header) - sizeof(uint32));
1233 	result -= sizeof(message_header) - sizeof(uint32);
1234 
1235 	if (result != B_OK || fHeader->format != MESSAGE_FORMAT_HAIKU
1236 		|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
1237 		free(fHeader);
1238 		fHeader = NULL;
1239 		_InitHeader();
1240 		return B_BAD_VALUE;
1241 	}
1242 
1243 	fHeader->fields_available = 0;
1244 	fHeader->data_available = 0;
1245 	what = fHeader->what;
1246 
1247 	if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) {
1248 		result = _Reference(fHeader);
1249 		if (result < B_OK)
1250 			return result;
1251 	} else {
1252 		fHeader->message_area = -1;
1253 
1254 		if (result == B_OK && fHeader->fields_size > 0) {
1255 			fFields = (field_header *)malloc(fHeader->fields_size);
1256 			if (!fFields)
1257 				return B_NO_MEMORY;
1258 
1259 			result = stream->Read(fFields, fHeader->fields_size);
1260 			result -= fHeader->fields_size;
1261 		}
1262 
1263 		if (result == B_OK && fHeader->data_size > 0) {
1264 			fData = (uint8 *)malloc(fHeader->data_size);
1265 			if (!fData)
1266 				return B_NO_MEMORY;
1267 
1268 			result = stream->Read(fData, fHeader->data_size);
1269 			result -= fHeader->data_size;
1270 		}
1271 
1272 		if (result < B_OK)
1273 			return B_BAD_VALUE;
1274 	}
1275 
1276 	return B_OK;
1277 }
1278 
1279 
1280 status_t
1281 BMessage::AddSpecifier(const char *property)
1282 {
1283 	DEBUG_FUNCTION_ENTER;
1284 	BMessage message(B_DIRECT_SPECIFIER);
1285 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1286 	if (result < B_OK)
1287 		return result;
1288 
1289 	return AddSpecifier(&message);
1290 }
1291 
1292 
1293 status_t
1294 BMessage::AddSpecifier(const char *property, int32 index)
1295 {
1296 	DEBUG_FUNCTION_ENTER;
1297 	BMessage message(B_INDEX_SPECIFIER);
1298 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1299 	if (result < B_OK)
1300 		return result;
1301 
1302 	result = message.AddInt32("index", index);
1303 	if (result < B_OK)
1304 		return result;
1305 
1306 	return AddSpecifier(&message);
1307 }
1308 
1309 
1310 status_t
1311 BMessage::AddSpecifier(const char *property, int32 index, int32 range)
1312 {
1313 	DEBUG_FUNCTION_ENTER;
1314 	if (range < 0)
1315 		return B_BAD_VALUE;
1316 
1317 	BMessage message(B_RANGE_SPECIFIER);
1318 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1319 	if (result < B_OK)
1320 		return result;
1321 
1322 	result = message.AddInt32("index", index);
1323 	if (result < B_OK)
1324 		return result;
1325 
1326 	result = message.AddInt32("range", range);
1327 	if (result < B_OK)
1328 		return result;
1329 
1330 	return AddSpecifier(&message);
1331 }
1332 
1333 
1334 status_t
1335 BMessage::AddSpecifier(const char *property, const char *name)
1336 {
1337 	DEBUG_FUNCTION_ENTER;
1338 	BMessage message(B_NAME_SPECIFIER);
1339 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1340 	if (result < B_OK)
1341 		return result;
1342 
1343 	result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1344 	if (result < B_OK)
1345 		return result;
1346 
1347 	return AddSpecifier(&message);
1348 }
1349 
1350 
1351 status_t
1352 BMessage::AddSpecifier(const BMessage *specifier)
1353 {
1354 	DEBUG_FUNCTION_ENTER;
1355 	status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1356 	if (result < B_OK)
1357 		return result;
1358 
1359 	fHeader->current_specifier++;
1360 	fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1361 	return B_OK;
1362 }
1363 
1364 
1365 status_t
1366 BMessage::SetCurrentSpecifier(int32 index)
1367 {
1368 	DEBUG_FUNCTION_ENTER;
1369 	if (index < 0)
1370 		return B_BAD_INDEX;
1371 
1372 	type_code type;
1373 	int32 count;
1374 	status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1375 	if (result < B_OK)
1376 		return result;
1377 
1378 	if (index > count)
1379 		return B_BAD_INDEX;
1380 
1381 	fHeader->current_specifier = index;
1382 	return B_OK;
1383 }
1384 
1385 
1386 status_t
1387 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *what,
1388 	const char **property) const
1389 {
1390 	DEBUG_FUNCTION_ENTER;
1391 
1392 	if (index)
1393 		*index = fHeader->current_specifier;
1394 
1395 	if (fHeader->current_specifier < 0
1396 		|| !(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED))
1397 		return B_BAD_SCRIPT_SYNTAX;
1398 
1399 	if (specifier) {
1400 		if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1401 			specifier) < B_OK)
1402 			return B_BAD_SCRIPT_SYNTAX;
1403 
1404 		if (what)
1405 			*what = specifier->what;
1406 
1407 		if (property) {
1408 			if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK)
1409 				return B_BAD_SCRIPT_SYNTAX;
1410 		}
1411 	}
1412 
1413 	return B_OK;
1414 }
1415 
1416 
1417 bool
1418 BMessage::HasSpecifiers() const
1419 {
1420 	DEBUG_FUNCTION_ENTER;
1421 	return fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS;
1422 }
1423 
1424 
1425 status_t
1426 BMessage::PopSpecifier()
1427 {
1428 	DEBUG_FUNCTION_ENTER;
1429 	if (fHeader->current_specifier < 0 ||
1430 		!(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED))
1431 		return B_BAD_VALUE;
1432 
1433 	if (fHeader->current_specifier >= 0)
1434 		fHeader->current_specifier--;
1435 
1436 	return B_OK;
1437 }
1438 
1439 
1440 status_t
1441 BMessage::_ResizeData(int32 offset, int32 change)
1442 {
1443 	if (change == 0)
1444 		return B_OK;
1445 
1446 	/* optimize for the most usual case: appending data */
1447 	if (offset < fHeader->data_size) {
1448 		field_header *field = fFields;
1449 		for (int32 i = 0; i < fHeader->field_count; i++, field++) {
1450 			if (field->offset >= offset)
1451 				field->offset += change;
1452 		}
1453 	}
1454 
1455 	if (change > 0) {
1456 		if (fHeader->data_available >= change) {
1457 			if (offset < fHeader->data_size) {
1458 				memmove(fData + offset + change, fData + offset,
1459 					fHeader->data_size - offset);
1460 			}
1461 
1462 			fHeader->data_available -= change;
1463 			fHeader->data_size += change;
1464 			return B_OK;
1465 		}
1466 
1467 		ssize_t size = fHeader->data_size * 2;
1468 		size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1469 		size = max_c(size, fHeader->data_size + change);
1470 
1471 		uint8 *newData = (uint8 *)realloc(fData, size);
1472 		if (size > 0 && !newData)
1473 			return B_NO_MEMORY;
1474 
1475 		fData = newData;
1476 		if (offset < fHeader->data_size) {
1477 			memmove(fData + offset + change, fData + offset,
1478 				fHeader->data_size - offset);
1479 		}
1480 
1481 		fHeader->data_size += change;
1482 		fHeader->data_available = size - fHeader->data_size;
1483 	} else {
1484 		ssize_t length = fHeader->data_size - offset + change;
1485 		if (length > 0)
1486 			memmove(fData + offset, fData + offset - change, length);
1487 
1488 		fHeader->data_size += change;
1489 		fHeader->data_available -= change;
1490 
1491 		if (fHeader->data_available > MAX_DATA_PREALLOCATION) {
1492 			ssize_t available = MAX_DATA_PREALLOCATION / 2;
1493 			ssize_t size = fHeader->data_size + available;
1494 			uint8 *newData = (uint8 *)realloc(fData, size);
1495 			if (size > 0 && !newData) {
1496 				// this is strange, but not really fatal
1497 				return B_OK;
1498 			}
1499 
1500 			fData = newData;
1501 			fHeader->data_available = available;
1502 		}
1503 	}
1504 
1505 	return B_OK;
1506 }
1507 
1508 
1509 uint32
1510 BMessage::_HashName(const char *name) const
1511 {
1512 	char ch;
1513 	uint32 result = 0;
1514 
1515 	while ((ch = *name++) != 0) {
1516 		result = (result << 7) ^ (result >> 24);
1517 		result ^= ch;
1518 	}
1519 
1520 	result ^= result << 12;
1521 	return result;
1522 }
1523 
1524 
1525 status_t
1526 BMessage::_FindField(const char *name, type_code type, field_header **result) const
1527 {
1528 	if (!name)
1529 		return B_BAD_VALUE;
1530 
1531 	if (!fHeader || !fFields || !fData)
1532 		return B_NAME_NOT_FOUND;
1533 
1534 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1535 	int32 nextField = fHeader->hash_table[hash];
1536 
1537 	while (nextField >= 0) {
1538 		field_header *field = &fFields[nextField];
1539 
1540 		if (strncmp((const char *)(fData + field->offset), name,
1541 			field->name_length) == 0) {
1542 			if (type != B_ANY_TYPE && field->type != type)
1543 				return B_BAD_TYPE;
1544 
1545 			*result = field;
1546 			return B_OK;
1547 		}
1548 
1549 		nextField = field->next_field;
1550 	}
1551 
1552 	return B_NAME_NOT_FOUND;
1553 }
1554 
1555 
1556 status_t
1557 BMessage::_AddField(const char *name, type_code type, bool isFixedSize,
1558 	field_header **result)
1559 {
1560 	if (!fHeader)
1561 		return B_ERROR;
1562 
1563 	if (fHeader->fields_available <= 0) {
1564 		int32 count = fHeader->field_count * 2 + 1;
1565 		count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1566 
1567 		field_header *newFields = (field_header *)realloc(fFields,
1568 			count * sizeof(field_header));
1569 		if (count > 0 && !newFields)
1570 			return B_NO_MEMORY;
1571 
1572 		fFields = newFields;
1573 		fHeader->fields_available = count - fHeader->field_count;
1574 	}
1575 
1576 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1577 	int32 *nextField = &fHeader->hash_table[hash];
1578 	while (*nextField >= 0)
1579 		nextField = &fFields[*nextField].next_field;
1580 	*nextField = fHeader->field_count;
1581 
1582 	field_header *field = &fFields[fHeader->field_count];
1583 	field->type = type;
1584 	field->count = 0;
1585 	field->data_size = 0;
1586 	field->allocated = 0;
1587 	field->next_field = -1;
1588 	field->offset = fHeader->data_size;
1589 	field->name_length = strlen(name) + 1;
1590 	status_t status = _ResizeData(field->offset, field->name_length);
1591 	if (status < B_OK)
1592 		return status;
1593 
1594 	memcpy(fData + field->offset, name, field->name_length);
1595 	field->flags = FIELD_FLAG_VALID;
1596 	if (isFixedSize)
1597 		field->flags |= FIELD_FLAG_FIXED_SIZE;
1598 
1599 	fHeader->fields_available--;
1600 	fHeader->fields_size += sizeof(field_header);
1601 	fHeader->field_count++;
1602 	*result = field;
1603 	return B_OK;
1604 }
1605 
1606 
1607 status_t
1608 BMessage::_RemoveField(field_header *field)
1609 {
1610 	status_t result = _ResizeData(field->offset, -(field->data_size
1611 		+ field->name_length));
1612 	if (result < B_OK)
1613 		return result;
1614 
1615 	int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header);
1616 	int32 nextField = field->next_field;
1617 	if (nextField > index)
1618 		nextField--;
1619 
1620 	int32 *value = fHeader->hash_table;
1621 	for (int32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1622 		if (*value > index)
1623 			*value -= 1;
1624 		else if (*value == index)
1625 			*value = nextField;
1626 	}
1627 
1628 	field_header *other = fFields;
1629 	for (int32 i = 0; i < fHeader->field_count; i++, other++) {
1630 		if (other->next_field > index)
1631 			other->next_field--;
1632 		else if (other->next_field == index)
1633 			other->next_field = nextField;
1634 	}
1635 
1636 	ssize_t size = fHeader->fields_size - (index + 1) * sizeof(field_header);
1637 	memmove(fFields + index, fFields + index + 1, size);
1638 	fHeader->fields_size -= sizeof(field_header);
1639 	fHeader->field_count--;
1640 	fHeader->fields_available++;
1641 
1642 	if (fHeader->fields_available > MAX_FIELD_PREALLOCATION) {
1643 		ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1644 		size = fHeader->fields_size + available * sizeof(field_header);
1645 		field_header *newFields = (field_header *)realloc(fFields, size);
1646 		if (size > 0 && !newFields) {
1647 			// this is strange, but not really fatal
1648 			return B_OK;
1649 		}
1650 
1651 		fFields = newFields;
1652 		fHeader->fields_available = available;
1653 	}
1654 
1655 	return B_OK;
1656 }
1657 
1658 
1659 status_t
1660 BMessage::AddData(const char *name, type_code type, const void *data,
1661 	ssize_t numBytes, bool isFixedSize, int32 count)
1662 {
1663 	DEBUG_FUNCTION_ENTER;
1664 	if (numBytes <= 0 || !data)
1665 		return B_BAD_VALUE;
1666 
1667 	if (fHeader->message_area >= 0)
1668 		_CopyForWrite();
1669 
1670 	field_header *field = NULL;
1671 	status_t result = _FindField(name, type, &field);
1672 	if (result == B_NAME_NOT_FOUND)
1673 		result = _AddField(name, type, isFixedSize, &field);
1674 
1675 	if (result < B_OK)
1676 		return result;
1677 
1678 	if (!field)
1679 		return B_ERROR;
1680 
1681 	uint32 offset = field->offset + field->name_length + field->data_size;
1682 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1683 		if (field->count) {
1684 			ssize_t size = field->data_size / field->count;
1685 			if (size != numBytes)
1686 				return B_BAD_VALUE;
1687 		}
1688 
1689 		result = _ResizeData(offset, numBytes);
1690 		if (result < B_OK) {
1691 			if (field->count == 0)
1692 				_RemoveField(field);
1693 			return result;
1694 		}
1695 
1696 		memcpy(fData + offset, data, numBytes);
1697 		field->data_size += numBytes;
1698 	} else {
1699 		int32 change = numBytes + sizeof(numBytes);
1700 		result = _ResizeData(offset, change);
1701 		if (result < B_OK) {
1702 			if (field->count == 0)
1703 				_RemoveField(field);
1704 			return result;
1705 		}
1706 
1707 		memcpy(fData + offset, &numBytes, sizeof(numBytes));
1708 		memcpy(fData + offset + sizeof(numBytes), data, numBytes);
1709 		field->data_size += change;
1710 	}
1711 
1712 	field->count++;
1713 	return B_OK;
1714 }
1715 
1716 
1717 status_t
1718 BMessage::RemoveData(const char *name, int32 index)
1719 {
1720 	DEBUG_FUNCTION_ENTER;
1721 	if (index < 0)
1722 		return B_BAD_VALUE;
1723 
1724 	if (fHeader->message_area >= 0)
1725 		_CopyForWrite();
1726 
1727 	field_header *field = NULL;
1728 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1729 
1730 	if (result < B_OK)
1731 		return result;
1732 
1733 	if (!field)
1734 		return B_ERROR;
1735 
1736 	if (index >= field->count)
1737 		return B_BAD_INDEX;
1738 
1739 	if (field->count == 1)
1740 		return _RemoveField(field);
1741 
1742 	uint32 offset = field->offset + field->name_length;
1743 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1744 		ssize_t size = field->data_size / field->count;
1745 		result = _ResizeData(offset + index * size, -size);
1746 		if (result < B_OK)
1747 			return result;
1748 
1749 		field->data_size -= size;
1750 	} else {
1751 		uint8 *pointer = fData + offset;
1752 
1753 		for (int32 i = 0; i < index; i++) {
1754 			offset += *(ssize_t *)pointer + sizeof(ssize_t);
1755 			pointer = fData + offset;
1756 		}
1757 
1758 		ssize_t currentSize = *(ssize_t *)pointer + sizeof(ssize_t);
1759 		result = _ResizeData(offset, -currentSize);
1760 		if (result < B_OK)
1761 			return result;
1762 
1763 		field->data_size -= currentSize;
1764 	}
1765 
1766 	field->count--;
1767 	return B_OK;
1768 }
1769 
1770 
1771 status_t
1772 BMessage::RemoveName(const char *name)
1773 {
1774 	DEBUG_FUNCTION_ENTER;
1775 	if (fHeader->message_area >= 0)
1776 		_CopyForWrite();
1777 
1778 	field_header *field = NULL;
1779 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1780 
1781 	if (result < B_OK)
1782 		return result;
1783 
1784 	if (!field)
1785 		return B_ERROR;
1786 
1787 	return _RemoveField(field);
1788 }
1789 
1790 
1791 status_t
1792 BMessage::MakeEmpty()
1793 {
1794 	DEBUG_FUNCTION_ENTER;
1795 	_Clear();
1796 	_InitHeader();
1797 	return B_OK;
1798 }
1799 
1800 
1801 status_t
1802 BMessage::FindData(const char *name, type_code type, int32 index,
1803 	const void **data, ssize_t *numBytes) const
1804 {
1805 	DEBUG_FUNCTION_ENTER;
1806 	if (!data || !numBytes)
1807 		return B_BAD_VALUE;
1808 
1809 	*data = NULL;
1810 	field_header *field = NULL;
1811 	status_t result = _FindField(name, type, &field);
1812 
1813 	if (result < B_OK)
1814 		return result;
1815 
1816 	if (!field)
1817 		return B_ERROR;
1818 
1819 	if (index < 0 || index >= field->count)
1820 		return B_BAD_INDEX;
1821 
1822 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1823 		*numBytes = field->data_size / field->count;
1824 		*data = fData + field->offset + field->name_length + index * *numBytes;
1825 	} else {
1826 		uint8 *pointer = fData + field->offset + field->name_length;
1827 
1828 		for (int32 i = 0; i < index; i++)
1829 			pointer += *(ssize_t *)pointer + sizeof(ssize_t);
1830 
1831 		*numBytes = *(ssize_t *)pointer;
1832 		*data = pointer + sizeof(ssize_t);
1833 	}
1834 
1835 	return B_OK;
1836 }
1837 
1838 
1839 status_t
1840 BMessage::ReplaceData(const char *name, type_code type, int32 index,
1841 	const void *data, ssize_t numBytes)
1842 {
1843 	DEBUG_FUNCTION_ENTER;
1844 	if (numBytes <= 0 || !data)
1845 		return B_BAD_VALUE;
1846 
1847 	field_header *field = NULL;
1848 	status_t result = _FindField(name, type, &field);
1849 
1850 	if (result < B_OK)
1851 		return result;
1852 
1853 	if (!field)
1854 		return B_ERROR;
1855 
1856 	if (index >= field->count)
1857 		return B_BAD_INDEX;
1858 
1859 	if (fHeader->message_area >= 0)
1860 		_CopyForWrite();
1861 
1862 	if (field->flags & FIELD_FLAG_FIXED_SIZE) {
1863 		ssize_t size = field->data_size / field->count;
1864 		if (size != numBytes)
1865 			return B_BAD_VALUE;
1866 
1867 		memcpy(fData + field->offset + field->name_length + index * size, data,
1868 			size);
1869 	} else {
1870 		uint32 offset = field->offset + field->name_length;
1871 		uint8 *pointer = fData + offset;
1872 
1873 		for (int32 i = 0; i < index; i++) {
1874 			offset += *(ssize_t *)pointer + sizeof(ssize_t);
1875 			pointer = fData + offset;
1876 		}
1877 
1878 		ssize_t currentSize = *(ssize_t *)pointer;
1879 		int32 change = numBytes - currentSize;
1880 		result = _ResizeData(offset, change);
1881 		if (result < B_OK)
1882 			return result;
1883 
1884 		memcpy(fData + offset, &numBytes, sizeof(numBytes));
1885 		memcpy(fData + offset + sizeof(numBytes), data, numBytes);
1886 		field->data_size += change;
1887 	}
1888 
1889 	return B_OK;
1890 }
1891 
1892 
1893 bool
1894 BMessage::HasData(const char *name, type_code type, int32 index) const
1895 {
1896 	DEBUG_FUNCTION_ENTER;
1897 	field_header *field = NULL;
1898 	status_t result = _FindField(name, type, &field);
1899 
1900 	if (result < B_OK)
1901 		return false;
1902 
1903 	if (!field)
1904 		return false;
1905 
1906 	if (index >= field->count)
1907 		return false;
1908 
1909 	return true;
1910 }
1911 
1912 
1913 /* Static functions for cache initialization and cleanup */
1914 void
1915 BMessage::_StaticInit()
1916 {
1917 	DEBUG_FUNCTION_ENTER2;
1918 	sReplyPorts[0] = create_port(1, "tmp_rport0");
1919 	sReplyPorts[1] = create_port(1, "tmp_rport1");
1920 	sReplyPorts[2] = create_port(1, "tmp_rport2");
1921 
1922 	sReplyPortInUse[0] = 0;
1923 	sReplyPortInUse[1] = 0;
1924 	sReplyPortInUse[2] = 0;
1925 
1926 	sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE);
1927 }
1928 
1929 
1930 void
1931 BMessage::_StaticCleanup()
1932 {
1933 	DEBUG_FUNCTION_ENTER2;
1934 	delete_port(sReplyPorts[0]);
1935 	sReplyPorts[0] = -1;
1936 	delete_port(sReplyPorts[1]);
1937 	sReplyPorts[1] = -1;
1938 	delete_port(sReplyPorts[2]);
1939 	sReplyPorts[2] = -1;
1940 }
1941 
1942 
1943 void
1944 BMessage::_StaticCacheCleanup()
1945 {
1946 	DEBUG_FUNCTION_ENTER2;
1947 	delete sMsgCache;
1948 	sMsgCache = NULL;
1949 }
1950 
1951 
1952 int32
1953 BMessage::_StaticGetCachedReplyPort()
1954 {
1955 	DEBUG_FUNCTION_ENTER2;
1956 	int index = -1;
1957 	for (int32 i = 0; i < sNumReplyPorts; i++) {
1958 		int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
1959 		if (old == 0) {
1960 			// This entry is free
1961 			index = i;
1962 			break;
1963 		} else {
1964 			// This entry is being used.
1965 			atomic_add(&(sReplyPortInUse[i]), -1);
1966 		}
1967 	}
1968 
1969 	return index;
1970 }
1971 
1972 
1973 status_t
1974 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
1975 	bigtime_t timeout, bool replyRequired, BMessenger &replyTo) const
1976 {
1977 	DEBUG_FUNCTION_ENTER;
1978 	ssize_t size = 0;
1979 	char *buffer = NULL;
1980 	message_header *header = NULL;
1981 	status_t result = B_OK;
1982 
1983 	BPrivate::BDirectMessageTarget* direct = NULL;
1984 	BMessage* copy = NULL;
1985 	if (portOwner == BPrivate::current_team())
1986 		BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
1987 
1988 	if (direct != NULL) {
1989 		// We have a direct local message target - we can just enqueue the message
1990 		// in its message queue. This will also prevent possible deadlocks when the
1991 		// queue is full.
1992 		copy = new BMessage(*this);
1993 		if (copy != NULL) {
1994 			header = copy->fHeader;
1995 			header->flags = fHeader->flags;
1996 		} else {
1997 			direct->Release();
1998 			return B_NO_MEMORY;
1999 		}
2000 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2001 	} else if (fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE * 10) {
2002 		// ToDo: bind the above size to the max port message size
2003 		// use message passing by area for such a large message
2004 		result = _FlattenToArea(&header);
2005 		if (result < B_OK)
2006 			return result;
2007 
2008 		buffer = (char *)header;
2009 		size = sizeof(message_header);
2010 
2011 		team_id target = portOwner;
2012 		if (target < 0) {
2013 			port_info info;
2014 			result = get_port_info(port, &info);
2015 			if (result < B_OK) {
2016 				free(header);
2017 				return result;
2018 			}
2019 			target = info.team;
2020 		}
2021 
2022 		void *address = NULL;
2023 		area_id transfered = _kern_transfer_area(header->message_area,
2024 			&address, B_ANY_ADDRESS, target);
2025 		if (transfered < B_OK) {
2026 			delete_area(header->message_area);
2027 			free(header);
2028 			return transfered;
2029 		}
2030 
2031 		header->message_area = transfered;
2032 #endif
2033 	} else {
2034 		size = _NativeFlattenedSize();
2035 		buffer = (char *)malloc(size);
2036 		if (buffer == NULL)
2037 			return B_NO_MEMORY;
2038 
2039 		result = _NativeFlatten(buffer, size);
2040 		if (result < B_OK) {
2041 			free(buffer);
2042 			return result;
2043 		}
2044 
2045 		header = (message_header *)buffer;
2046 	}
2047 
2048 	if (!replyTo.IsValid()) {
2049 		BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
2050 			fHeader->reply_port, fHeader->reply_target);
2051 
2052 		if (!replyTo.IsValid())
2053 			replyTo = be_app_messenger;
2054 	}
2055 
2056 	BMessenger::Private replyToPrivate(replyTo);
2057 
2058 	if (replyRequired) {
2059 		header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
2060 		header->flags &= ~MESSAGE_FLAG_REPLY_DONE;
2061 	}
2062 
2063 	header->target = token;
2064 	header->reply_team = replyToPrivate.Team();
2065 	header->reply_port = replyToPrivate.Port();
2066 	header->reply_target = replyToPrivate.Token();
2067 	header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2068 
2069 	if (direct == NULL) {
2070 		KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, "
2071 			"message: '%c%c%c%c'", portOwner, port, token,
2072 			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2073 
2074 		do {
2075 			result = write_port_etc(port, kPortMessageCode, (void *)buffer, size,
2076 				B_RELATIVE_TIMEOUT, timeout);
2077 		} while (result == B_INTERRUPTED);
2078 	}
2079 
2080 	if (result == B_OK && IsSourceWaiting()) {
2081 		// the forwarded message will handle the reply - we must not do
2082 		// this anymore
2083 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
2084 	}
2085 
2086 	// we need to do this last because it is possible our
2087 	// message might be destroyed after it's enqueued in the
2088 	// target looper. Thus we don't want to do any ops that depend on
2089 	// members of this after the enqueue.
2090 	if (direct != NULL) {
2091 		KTRACE("BMessage send direct: port: %ld, token: %ld, "
2092 			"message: '%c%c%c%c'", port, token,
2093 			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2094 
2095 		// this is a local message transmission
2096 		direct->AddMessage(copy);
2097 		if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
2098 			// there is currently no message waiting, and we need to wakeup the looper
2099 			write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
2100 		}
2101 		direct->Release();
2102 	}
2103 
2104 	free(buffer);
2105 	return result;
2106 }
2107 
2108 
2109 /*!
2110 	Sends a message and waits synchronously for a reply.
2111 */
2112 status_t
2113 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2114 	BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
2115 {
2116 	if (IsSourceWaiting()) {
2117 		// we can't forward this message synchronously when it's already
2118 		// waiting for a reply
2119 		return B_ERROR;
2120 	}
2121 
2122 	DEBUG_FUNCTION_ENTER;
2123 	const int32 cachedReplyPort = _StaticGetCachedReplyPort();
2124 	port_id replyPort = B_BAD_PORT_ID;
2125 	status_t result = B_OK;
2126 
2127 	if (cachedReplyPort < B_OK) {
2128 		// All the cached reply ports are in use; create a new one
2129 		replyPort = create_port(1 /* for one message */, "tmp_reply_port");
2130 		if (replyPort < B_OK)
2131 			return replyPort;
2132 	} else {
2133 		assert(cachedReplyPort < sNumReplyPorts);
2134 		replyPort = sReplyPorts[cachedReplyPort];
2135 	}
2136 
2137 	team_id team = B_BAD_TEAM_ID;
2138 	if (be_app != NULL)
2139 		team = be_app->Team();
2140 	else {
2141 		port_info portInfo;
2142 		result = get_port_info(replyPort, &portInfo);
2143 		if (result < B_OK)
2144 			goto error;
2145 
2146 		team = portInfo.team;
2147 	}
2148 
2149 	result = set_port_owner(replyPort, portOwner);
2150 	if (result < B_OK)
2151 		goto error;
2152 
2153 	// tests if the queue of the reply port is really empty
2154 #if 0
2155 	port_info portInfo;
2156 	if (get_port_info(replyPort, &portInfo) == B_OK
2157 		&& portInfo.queue_count > 0) {
2158 		debugger("reply port not empty!");
2159 		printf("  reply port not empty! %ld message(s) in queue\n",
2160 			portInfo.queue_count);
2161 
2162 		// fetch and print the messages
2163 		for (int32 i = 0; i < portInfo.queue_count; i++) {
2164 			char buffer[1024];
2165 			int32 code;
2166 			ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer));
2167 			if (size < 0) {
2168 				printf("failed to read message from reply port\n");
2169 				continue;
2170 			}
2171 			if (size >= (ssize_t)sizeof(buffer)) {
2172 				printf("message from reply port too big\n");
2173 				continue;
2174 			}
2175 
2176 			BMemoryIO stream(buffer, size);
2177 			BMessage reply;
2178 			if (reply.Unflatten(&stream) != B_OK) {
2179 				printf("failed to unflatten message from reply port\n");
2180 				continue;
2181 			}
2182 
2183 			printf("message %ld from reply port:\n", i);
2184 			reply.PrintToStream();
2185 		}
2186 	}
2187 #endif
2188 
2189 	{
2190 		BMessenger replyTarget;
2191 		BMessenger::Private(replyTarget).SetTo(team, replyPort,
2192 			B_PREFERRED_TOKEN);
2193 		// TODO: replying could also use a BDirectMessageTarget like mechanism for local targets
2194 		result = _SendMessage(port, -1, token, sendTimeout, true,
2195 			replyTarget);
2196 	}
2197 
2198 	if (result < B_OK)
2199 		goto error;
2200 
2201 	int32 code;
2202 	result = handle_reply(replyPort, &code, replyTimeout, reply);
2203 	if (result < B_OK && cachedReplyPort >= 0) {
2204 		delete_port(replyPort);
2205 		sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
2206 	}
2207 
2208 error:
2209 	if (cachedReplyPort >= 0) {
2210 		// Reclaim ownership of cached port
2211 		set_port_owner(replyPort, team);
2212 		// Flag as available
2213 		atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
2214 		return result;
2215 	}
2216 
2217 	delete_port(replyPort);
2218 	return result;
2219 }
2220 
2221 
2222 status_t
2223 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
2224 	int32 token, bigtime_t timeout)
2225 {
2226 	DEBUG_FUNCTION_ENTER2;
2227 	if (!data)
2228 		return B_BAD_VALUE;
2229 
2230 	uint32 magic = *(uint32 *)data;
2231 
2232 	if (magic == MESSAGE_FORMAT_HAIKU || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) {
2233 		message_header *header = (message_header *)data;
2234 		header->target = token;
2235 		header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2236 	} else if (magic == MESSAGE_FORMAT_R5) {
2237 		uint8 *header = (uint8 *)data;
2238 		header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
2239 			+ sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
2240 			+ sizeof(uint8) /* flags */;
2241 		*(int32 *)header = token;
2242 	} else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) {
2243 		KMessage::Header *header = (KMessage::Header *)data;
2244 		header->targetToken = token;
2245 	} else {
2246 		return B_NOT_A_MESSAGE;
2247 	}
2248 
2249 	// send the message
2250 	status_t result;
2251 
2252 	do {
2253 		result = write_port_etc(port, kPortMessageCode, data, size,
2254 			B_RELATIVE_TIMEOUT, timeout);
2255 	} while (result == B_INTERRUPTED);
2256 
2257 	return result;
2258 }
2259 
2260 
2261 void BMessage::_ReservedMessage1(void) {};
2262 void BMessage::_ReservedMessage2(void) {};
2263 void BMessage::_ReservedMessage3(void) {};
2264 
2265 
2266 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
2267 
2268 #define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
2269 status_t																	\
2270 BMessage::Add##typeName(const char *name, type val)							\
2271 {																			\
2272 	return AddData(name, typeCode, &val, sizeof(type), true);				\
2273 }																			\
2274 																			\
2275 status_t																	\
2276 BMessage::Find##typeName(const char *name, type *p) const					\
2277 {																			\
2278 	void *ptr = NULL;														\
2279 	ssize_t bytes = 0;														\
2280 	status_t error = B_OK;													\
2281 																			\
2282 	*p = type();															\
2283 	error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes);		\
2284 																			\
2285 	if (error == B_OK)														\
2286 		memcpy(p, ptr, sizeof(type));										\
2287 																			\
2288 	return error;															\
2289 }																			\
2290 																			\
2291 status_t																	\
2292 BMessage::Find##typeName(const char *name, int32 index, type *p) const		\
2293 {																			\
2294 	void *ptr = NULL;														\
2295 	ssize_t bytes = 0;														\
2296 	status_t error = B_OK;													\
2297 																			\
2298 	*p = type();															\
2299 	error = FindData(name, typeCode, index, (const void **)&ptr, &bytes);	\
2300 																			\
2301 	if (error == B_OK)														\
2302 		memcpy(p, ptr, sizeof(type));										\
2303 																			\
2304 	return error;															\
2305 }																			\
2306 																			\
2307 status_t																	\
2308 BMessage::Replace##typeName(const char *name, type val)						\
2309 {																			\
2310 	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
2311 }																			\
2312 																			\
2313 status_t																	\
2314 BMessage::Replace##typeName(const char *name, int32 index, type val)		\
2315 {																			\
2316 	return ReplaceData(name, typeCode, index, &val, sizeof(type));			\
2317 }																			\
2318 																			\
2319 bool																		\
2320 BMessage::Has##typeName(const char *name, int32 index) const				\
2321 {																			\
2322 	return HasData(name, typeCode, index);									\
2323 }
2324 
2325 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2326 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2327 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2328 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2329 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2330 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2331 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2332 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2333 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2334 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2335 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2336 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2337 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2338 
2339 #undef DEFINE_FUNCTIONS
2340 
2341 #define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
2342 bool																		\
2343 BMessage::Has##typeName(const char *name, int32 index) const				\
2344 {																			\
2345 	return HasData(name, typeCode, index);									\
2346 }
2347 
2348 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2349 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2350 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2351 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2352 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2353 
2354 #undef DEFINE_HAS_FUNCTION
2355 
2356 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
2357 type																		\
2358 BMessage::Find##typeName(const char *name, int32 index) const				\
2359 {																			\
2360 	type val = initialize;													\
2361 	Find##typeName(name, index, &val);										\
2362 	return val;																\
2363 }
2364 
2365 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2366 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2367 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
2368 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2369 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2370 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2371 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2372 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2373 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2374 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2375 
2376 #undef DEFINE_LAZY_FIND_FUNCTION
2377 
2378 status_t
2379 BMessage::AddString(const char *name, const char *string)
2380 {
2381 	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false);
2382 }
2383 
2384 
2385 status_t
2386 BMessage::AddString(const char *name, const BString &string)
2387 {
2388 	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
2389 }
2390 
2391 
2392 status_t
2393 BMessage::AddPointer(const char *name, const void *pointer)
2394 {
2395 	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2396 }
2397 
2398 
2399 status_t
2400 BMessage::AddMessenger(const char *name, BMessenger messenger)
2401 {
2402 	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2403 }
2404 
2405 
2406 status_t
2407 BMessage::AddRef(const char *name, const entry_ref *ref)
2408 {
2409 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2410 	char buffer[size];
2411 
2412 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2413 
2414 	if (error >= B_OK)
2415 		error = AddData(name, B_REF_TYPE, buffer, size, false);
2416 
2417 	return error;
2418 }
2419 
2420 
2421 status_t
2422 BMessage::AddMessage(const char *name, const BMessage *message)
2423 {
2424 	if (message == NULL)
2425 		return B_BAD_VALUE;
2426 
2427 	// TODO: This and the following functions waste time by allocating and
2428 	// copying an extra buffer. Functions can be added that return a direct
2429 	// pointer into the message.
2430 
2431 	char stackBuffer[16384];
2432 	ssize_t size = message->FlattenedSize();
2433 
2434 	char* buffer;
2435 	if (size > (ssize_t)sizeof(stackBuffer)) {
2436 		buffer = static_cast<char*>(malloc(size));
2437 		if (buffer == NULL)
2438 			return B_NO_MEMORY;
2439 	} else
2440 		buffer = stackBuffer;
2441 
2442 	status_t error = message->Flatten(buffer, size);
2443 
2444 	if (error >= B_OK)
2445 		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
2446 
2447 	if (buffer != stackBuffer)
2448 		free(buffer);
2449 
2450 	return error;
2451 }
2452 
2453 
2454 status_t
2455 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
2456 {
2457 	if (object == NULL)
2458 		return B_BAD_VALUE;
2459 
2460 	char stackBuffer[16384];
2461 	ssize_t size = object->FlattenedSize();
2462 
2463 	char* buffer;
2464 	if (size > (ssize_t)sizeof(stackBuffer)) {
2465 		buffer = static_cast<char*>(malloc(size));
2466 		if (buffer == NULL)
2467 			return B_NO_MEMORY;
2468 	} else
2469 		buffer = stackBuffer;
2470 
2471 	status_t error = object->Flatten(buffer, size);
2472 
2473 	if (error >= B_OK)
2474 		error = AddData(name, object->TypeCode(), buffer, size, false);
2475 
2476 	if (buffer != stackBuffer)
2477 		free(buffer);
2478 
2479 	return error;
2480 }
2481 
2482 
2483 status_t
2484 BMessage::FindString(const char *name, const char **string) const
2485 {
2486 	return FindString(name, 0, string);
2487 }
2488 
2489 
2490 status_t
2491 BMessage::FindString(const char *name, int32 index, const char **string) const
2492 {
2493 	ssize_t bytes;
2494 	return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes);
2495 }
2496 
2497 
2498 status_t
2499 BMessage::FindString(const char *name, BString *string) const
2500 {
2501 	return FindString(name, 0, string);
2502 }
2503 
2504 
2505 status_t
2506 BMessage::FindString(const char *name, int32 index, BString *string) const
2507 {
2508 	if (string == NULL)
2509 		return B_BAD_VALUE;
2510 
2511 	const char *cstr;
2512 	status_t error = FindString(name, index, &cstr);
2513 	if (error < B_OK)
2514 		return error;
2515 
2516 	*string = cstr;
2517 	return B_OK;
2518 }
2519 
2520 
2521 status_t
2522 BMessage::FindPointer(const char *name, void **pointer) const
2523 {
2524 	return FindPointer(name, 0, pointer);
2525 }
2526 
2527 
2528 status_t
2529 BMessage::FindPointer(const char *name, int32 index, void **pointer) const
2530 {
2531 	if (pointer == NULL)
2532 		return B_BAD_VALUE;
2533 
2534 	void **data = NULL;
2535 	ssize_t size = 0;
2536 	status_t error = FindData(name, B_POINTER_TYPE, index,
2537 		(const void **)&data, &size);
2538 
2539 	if (error == B_OK)
2540 		*pointer = *data;
2541 	else
2542 		*pointer = NULL;
2543 
2544 	return error;
2545 }
2546 
2547 
2548 status_t
2549 BMessage::FindMessenger(const char *name, BMessenger *messenger) const
2550 {
2551 	return FindMessenger(name, 0, messenger);
2552 }
2553 
2554 
2555 status_t
2556 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger)
2557 	const
2558 {
2559 	if (messenger == NULL)
2560 		return B_BAD_VALUE;
2561 
2562 	void *data = NULL;
2563 	ssize_t size = 0;
2564 	status_t error = FindData(name, B_MESSENGER_TYPE, index,
2565 		(const void **)&data, &size);
2566 
2567 	if (error == B_OK)
2568 		memcpy(messenger, data, sizeof(BMessenger));
2569 	else
2570 		*messenger = BMessenger();
2571 
2572 	return error;
2573 }
2574 
2575 
2576 status_t
2577 BMessage::FindRef(const char *name, entry_ref *ref) const
2578 {
2579 	return FindRef(name, 0, ref);
2580 }
2581 
2582 
2583 status_t
2584 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const
2585 {
2586 	if (ref == NULL)
2587 		return B_BAD_VALUE;
2588 
2589 	void *data = NULL;
2590 	ssize_t size = 0;
2591 	status_t error = FindData(name, B_REF_TYPE, index,
2592 		(const void **)&data, &size);
2593 
2594 	if (error == B_OK)
2595 		error = BPrivate::entry_ref_unflatten(ref, (char *)data, size);
2596 	else
2597 		*ref = entry_ref();
2598 
2599 	return error;
2600 }
2601 
2602 
2603 status_t
2604 BMessage::FindMessage(const char *name, BMessage *message) const
2605 {
2606 	return FindMessage(name, 0, message);
2607 }
2608 
2609 
2610 status_t
2611 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const
2612 {
2613 	if (message == NULL)
2614 		return B_BAD_VALUE;
2615 
2616 	void *data = NULL;
2617 	ssize_t size = 0;
2618 	status_t error = FindData(name, B_MESSAGE_TYPE, index,
2619 		(const void **)&data, &size);
2620 
2621 	if (error == B_OK)
2622 		error = message->Unflatten((const char *)data);
2623 	else
2624 		*message = BMessage();
2625 
2626 	return error;
2627 }
2628 
2629 
2630 status_t
2631 BMessage::FindFlat(const char *name, BFlattenable *object) const
2632 {
2633 	return FindFlat(name, 0, object);
2634 }
2635 
2636 
2637 status_t
2638 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const
2639 {
2640 	if (object == NULL)
2641 		return B_BAD_VALUE;
2642 
2643 	void *data = NULL;
2644 	ssize_t numBytes = 0;
2645 	status_t error = FindData(name, object->TypeCode(), index,
2646 		(const void **)&data, &numBytes);
2647 
2648 	if (error == B_OK)
2649 		error = object->Unflatten(object->TypeCode(), data, numBytes);
2650 
2651 	return error;
2652 }
2653 
2654 
2655 status_t
2656 BMessage::FindData(const char *name, type_code type, const void **data,
2657 	ssize_t *numBytes) const
2658 {
2659 	return FindData(name, type, 0, data, numBytes);
2660 }
2661 
2662 
2663 status_t
2664 BMessage::ReplaceString(const char *name, const char *string)
2665 {
2666 	if (string == NULL)
2667 		return B_BAD_VALUE;
2668 
2669 	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
2670 }
2671 
2672 
2673 status_t
2674 BMessage::ReplaceString(const char *name, int32 index, const char *string)
2675 {
2676 	if (string == NULL)
2677 		return B_BAD_VALUE;
2678 
2679 	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
2680 }
2681 
2682 
2683 status_t
2684 BMessage::ReplaceString(const char *name, const BString &string)
2685 {
2686 	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
2687 		string.Length() + 1);
2688 }
2689 
2690 
2691 status_t
2692 BMessage::ReplaceString(const char *name, int32 index, const BString &string)
2693 {
2694 	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
2695 		string.Length() + 1);
2696 }
2697 
2698 
2699 status_t
2700 BMessage::ReplacePointer(const char *name, const void *pointer)
2701 {
2702 	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2703 }
2704 
2705 
2706 status_t
2707 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2708 {
2709 	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2710 }
2711 
2712 
2713 status_t
2714 BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2715 {
2716 	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2717 		sizeof(BMessenger));
2718 }
2719 
2720 
2721 status_t
2722 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2723 {
2724 	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2725 		sizeof(BMessenger));
2726 }
2727 
2728 
2729 status_t
2730 BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2731 {
2732 	return ReplaceRef(name, 0, ref);
2733 }
2734 
2735 
2736 status_t
2737 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
2738 {
2739 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2740 	char buffer[size];
2741 
2742 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2743 
2744 	if (error >= B_OK)
2745 		error = ReplaceData(name, B_REF_TYPE, index, &buffer, size);
2746 
2747 	return error;
2748 }
2749 
2750 
2751 status_t
2752 BMessage::ReplaceMessage(const char *name, const BMessage *message)
2753 {
2754 	return ReplaceMessage(name, 0, message);
2755 }
2756 
2757 
2758 status_t
2759 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message)
2760 {
2761 	if (message == NULL)
2762 		return B_BAD_VALUE;
2763 
2764 	ssize_t size = message->FlattenedSize();
2765 	char buffer[size];
2766 
2767 	status_t error = message->Flatten(buffer, size);
2768 
2769 	if (error >= B_OK)
2770 		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
2771 
2772 	return error;
2773 }
2774 
2775 
2776 status_t
2777 BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2778 {
2779 	return ReplaceFlat(name, 0, object);
2780 }
2781 
2782 
2783 status_t
2784 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
2785 {
2786 	if (object == NULL)
2787 		return B_BAD_VALUE;
2788 
2789 	ssize_t size = object->FlattenedSize();
2790 	char buffer[size];
2791 
2792 	status_t error = object->Flatten(buffer, size);
2793 
2794 	if (error >= B_OK)
2795 		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
2796 
2797 	return error;
2798 }
2799 
2800 
2801 status_t
2802 BMessage::ReplaceData(const char *name, type_code type, const void *data,
2803 	ssize_t numBytes)
2804 {
2805 	return ReplaceData(name, type, 0, data, numBytes);
2806 }
2807 
2808 
2809 bool
2810 BMessage::HasFlat(const char *name, const BFlattenable *object) const
2811 {
2812 	return HasFlat(name, 0, object);
2813 }
2814 
2815 
2816 bool
2817 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2818 	const
2819 {
2820 	return HasData(name, object->TypeCode(), index);
2821 }
2822