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