xref: /haiku/src/kits/app/Message.cpp (revision a76f629efad0ba4d6518d918a39dbcc6097fe536)
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 			if ((field->flags & FIELD_FLAG_FIXED_SIZE) == 0) {
579 				size = *(uint32 *)pointer;
580 				pointer += sizeof(uint32);
581 			}
582 
583 			switch (field->type) {
584 				case B_RECT_TYPE:
585 					print_to_stream_type<BRect>(pointer);
586 					break;
587 
588 				case B_POINT_TYPE:
589 					print_to_stream_type<BPoint>(pointer);
590 					break;
591 
592 				case B_STRING_TYPE:
593 					printf("string(\"%.*s\", %ld bytes)\n", (int)size,
594 						(char *)pointer, (long)size);
595 					break;
596 
597 				case B_INT8_TYPE:
598 					print_type<int8>("int8(0x%hx or %d or '%.1s')\n", pointer);
599 					break;
600 
601 				case B_UINT8_TYPE:
602 					print_type<uint8>("uint8(0x%hx or %u or '%.1s')\n",
603 						pointer);
604 					break;
605 
606 				case B_INT16_TYPE:
607 					print_type<int16>("int16(0x%x or %d)\n", pointer);
608 					break;
609 
610 				case B_UINT16_TYPE:
611 					print_type<uint16>("uint16(0x%x or %u\n", pointer);
612 					break;
613 
614 				case B_INT32_TYPE:
615 					print_type<int32>("int32(0x%lx or %ld)\n", pointer);
616 					break;
617 
618 				case B_UINT32_TYPE:
619 					print_type<uint32>("uint32(0x%lx or %lu\n", pointer);
620 					break;
621 
622 				case B_INT64_TYPE:
623 					print_type<int64>("int64(0x%Lx or %Ld)\n", pointer);
624 					break;
625 
626 				case B_UINT64_TYPE:
627 					print_type<uint64>("uint64(0x%Lx or %Ld\n", pointer);
628 					break;
629 
630 				case B_BOOL_TYPE:
631 					printf("bool(%s)\n", *((bool *)pointer) != 0
632 						? "true" : "false");
633 					break;
634 
635 				case B_FLOAT_TYPE:
636 					print_type<float>("float(%.4f)\n", pointer);
637 					break;
638 
639 				case B_DOUBLE_TYPE:
640 					print_type<double>("double(%.8f)\n", pointer);
641 					break;
642 
643 				case B_REF_TYPE:
644 				{
645 					entry_ref ref;
646 					BPrivate::entry_ref_unflatten(&ref, (char *)pointer, size);
647 
648 					printf("entry_ref(device=%d, directory=%" B_PRIdINO
649 						", name=\"%s\", ", (int)ref.device, ref.directory,
650 						ref.name);
651 
652 					BPath path(&ref);
653 					printf("path=\"%s\")\n", path.Path());
654 					break;
655 				}
656 
657 				case B_MESSAGE_TYPE:
658 				{
659 					char buffer[1024];
660 					sprintf(buffer, "%s        ", indent);
661 
662 					BMessage message;
663 					status_t result = message.Unflatten((const char *)pointer);
664 					if (result != B_OK) {
665 						printf("failed unflatten: %s\n", strerror(result));
666 						break;
667 					}
668 
669 					message._PrintToStream(buffer);
670 					printf("%s        }\n", indent);
671 					break;
672 				}
673 
674 				default:
675 				{
676 					printf("(type = '%.4s')(size = %ld)\n", (char *)&value,
677 						(long)size);
678 					break;
679 				}
680 			}
681 
682 			pointer += size;
683 		}
684 	}
685 }
686 
687 
688 status_t
689 BMessage::Rename(const char *oldEntry, const char *newEntry)
690 {
691 	DEBUG_FUNCTION_ENTER;
692 	if (oldEntry == NULL || newEntry == NULL)
693 		return B_BAD_VALUE;
694 
695 	if (fHeader->message_area >= 0)
696 		_CopyForWrite();
697 
698 	uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
699 	int32 *nextField = &fHeader->hash_table[hash];
700 
701 	while (*nextField >= 0) {
702 		field_header *field = &fFields[*nextField];
703 
704 		if (strncmp((const char *)(fData + field->offset), oldEntry,
705 			field->name_length) == 0) {
706 			// nextField points to the field for oldEntry, save it and unlink
707 			int32 index = *nextField;
708 			*nextField = field->next_field;
709 			field->next_field = -1;
710 
711 			hash = _HashName(newEntry) % fHeader->hash_table_size;
712 			nextField = &fHeader->hash_table[hash];
713 			while (*nextField >= 0)
714 				nextField = &fFields[*nextField].next_field;
715 			*nextField = index;
716 
717 			int32 newLength = strlen(newEntry) + 1;
718 			status_t result = _ResizeData(field->offset + 1,
719 				newLength - field->name_length);
720 			if (result < B_OK)
721 				return result;
722 
723 			memcpy(fData + field->offset, newEntry, newLength);
724 			field->name_length = newLength;
725 			return B_OK;
726 		}
727 
728 		nextField = &field->next_field;
729 	}
730 
731 	return B_NAME_NOT_FOUND;
732 }
733 
734 
735 bool
736 BMessage::WasDelivered() const
737 {
738 	DEBUG_FUNCTION_ENTER;
739 	return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0;
740 }
741 
742 
743 bool
744 BMessage::IsSourceWaiting() const
745 {
746 	DEBUG_FUNCTION_ENTER;
747 	return (fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0
748 		&& (fHeader->flags & MESSAGE_FLAG_REPLY_DONE) == 0;
749 }
750 
751 
752 bool
753 BMessage::IsSourceRemote() const
754 {
755 	DEBUG_FUNCTION_ENTER;
756 	return (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0
757 		&& fHeader->reply_team != BPrivate::current_team();
758 }
759 
760 
761 BMessenger
762 BMessage::ReturnAddress() const
763 {
764 	DEBUG_FUNCTION_ENTER;
765 	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) != 0) {
766 		BMessenger messenger;
767 		BMessenger::Private(messenger).SetTo(fHeader->reply_team,
768 			fHeader->reply_port, fHeader->reply_target);
769 		return messenger;
770 	}
771 
772 	return BMessenger();
773 }
774 
775 
776 const BMessage *
777 BMessage::Previous() const
778 {
779 	DEBUG_FUNCTION_ENTER;
780 	/* ToDo: test if the "_previous_" field is used in R5 */
781 	if (fOriginal == NULL) {
782 		fOriginal = new BMessage();
783 
784 		if (FindMessage("_previous_", fOriginal) != B_OK) {
785 			delete fOriginal;
786 			fOriginal = NULL;
787 		}
788 	}
789 
790 	return fOriginal;
791 }
792 
793 
794 bool
795 BMessage::WasDropped() const
796 {
797 	DEBUG_FUNCTION_ENTER;
798 	return (fHeader->flags & MESSAGE_FLAG_WAS_DROPPED) != 0;
799 }
800 
801 
802 BPoint
803 BMessage::DropPoint(BPoint *offset) const
804 {
805 	DEBUG_FUNCTION_ENTER;
806 	if (offset)
807 		*offset = FindPoint("_drop_offset_");
808 
809 	return FindPoint("_drop_point_");
810 }
811 
812 
813 status_t
814 BMessage::SendReply(uint32 command, BHandler *replyTo)
815 {
816 	DEBUG_FUNCTION_ENTER;
817 	BMessage message(command);
818 	return SendReply(&message, replyTo);
819 }
820 
821 
822 status_t
823 BMessage::SendReply(BMessage *reply, BHandler *replyTo, bigtime_t timeout)
824 {
825 	DEBUG_FUNCTION_ENTER;
826 	BMessenger messenger(replyTo);
827 	return SendReply(reply, messenger, timeout);
828 }
829 
830 
831 status_t
832 BMessage::SendReply(BMessage *reply, BMessenger replyTo, bigtime_t timeout)
833 {
834 	DEBUG_FUNCTION_ENTER;
835 	BMessenger messenger;
836 	BMessenger::Private messengerPrivate(messenger);
837 	messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
838 		fHeader->reply_target);
839 
840 	if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
841 		if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
842 			return B_DUPLICATE_REPLY;
843 
844 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
845 		reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
846 		status_t result = messenger.SendMessage(reply, replyTo, timeout);
847 		reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
848 
849 		if (result != B_OK) {
850 			if (set_port_owner(messengerPrivate.Port(),
851 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
852 				delete_port(messengerPrivate.Port());
853 			}
854 		}
855 
856 		return result;
857 	}
858 
859 	// no reply required
860 	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
861 		return B_BAD_REPLY;
862 
863 	reply->AddMessage("_previous_", this);
864 	reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
865 	status_t result = messenger.SendMessage(reply, replyTo, timeout);
866 	reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
867 	reply->RemoveName("_previous_");
868 	return result;
869 }
870 
871 
872 status_t
873 BMessage::SendReply(uint32 command, BMessage *replyToReply)
874 {
875 	DEBUG_FUNCTION_ENTER;
876 	BMessage message(command);
877 	return SendReply(&message, replyToReply);
878 }
879 
880 
881 status_t
882 BMessage::SendReply(BMessage *reply, BMessage *replyToReply,
883 	bigtime_t sendTimeout, bigtime_t replyTimeout)
884 {
885 	DEBUG_FUNCTION_ENTER;
886 	BMessenger messenger;
887 	BMessenger::Private messengerPrivate(messenger);
888 	messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
889 		fHeader->reply_target);
890 
891 	if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
892 		if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
893 			return B_DUPLICATE_REPLY;
894 
895 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
896 		reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
897 		status_t result = messenger.SendMessage(reply, replyToReply,
898 			sendTimeout, replyTimeout);
899 		reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
900 
901 		if (result != B_OK) {
902 			if (set_port_owner(messengerPrivate.Port(),
903 				messengerPrivate.Team()) == B_BAD_TEAM_ID) {
904 				delete_port(messengerPrivate.Port());
905 			}
906 		}
907 
908 		return result;
909 	}
910 
911 	// no reply required
912 	if ((fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
913 		return B_BAD_REPLY;
914 
915 	reply->AddMessage("_previous_", this);
916 	reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
917 	status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout,
918 		replyTimeout);
919 	reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
920 	reply->RemoveName("_previous_");
921 	return result;
922 }
923 
924 
925 ssize_t
926 BMessage::FlattenedSize() const
927 {
928 	DEBUG_FUNCTION_ENTER;
929 	return sizeof(message_header) + fHeader->field_count * sizeof(field_header)
930 		+ fHeader->data_size;
931 }
932 
933 
934 status_t
935 BMessage::Flatten(char *buffer, ssize_t size) const
936 {
937 	DEBUG_FUNCTION_ENTER;
938 	if (buffer == NULL || size < 0)
939 		return B_BAD_VALUE;
940 
941 	if (fHeader == NULL)
942 		return B_NO_INIT;
943 
944 	/* we have to sync the what code as it is a public member */
945 	fHeader->what = what;
946 
947 	memcpy(buffer, fHeader, min_c(sizeof(message_header), (size_t)size));
948 	buffer += sizeof(message_header);
949 	size -= sizeof(message_header);
950 
951 	size_t fieldsSize = fHeader->field_count * sizeof(field_header);
952 	memcpy(buffer, fFields, min_c(fieldsSize, (size_t)size));
953 	buffer += fieldsSize;
954 	size -= fieldsSize;
955 
956 	memcpy(buffer, fData, min_c(fHeader->data_size, (size_t)size));
957 	if ((size_t)size < fHeader->data_size)
958 		return B_BUFFER_OVERFLOW;
959 
960 	return B_OK;
961 }
962 
963 
964 status_t
965 BMessage::Flatten(BDataIO *stream, ssize_t *size) const
966 {
967 	DEBUG_FUNCTION_ENTER;
968 	if (stream == NULL)
969 		return B_BAD_VALUE;
970 
971 	if (fHeader == NULL)
972 		return B_NO_INIT;
973 
974 	/* we have to sync the what code as it is a public member */
975 	fHeader->what = what;
976 
977 	ssize_t result1 = stream->Write(fHeader, sizeof(message_header));
978 	if (result1 != sizeof(message_header))
979 		return result1 < 0 ? result1 : B_ERROR;
980 
981 	ssize_t result2 = 0;
982 	if (fHeader->field_count > 0) {
983 		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
984 		result2 = stream->Write(fFields, fieldsSize);
985 		if (result2 != fieldsSize)
986 			return result2 < 0 ? result2 : B_ERROR;
987 	}
988 
989 	ssize_t result3 = 0;
990 	if (fHeader->data_size > 0) {
991 		result3 = stream->Write(fData, fHeader->data_size);
992 		if (result3 != (ssize_t)fHeader->data_size)
993 			return result3 < 0 ? result3 : B_ERROR;
994 	}
995 
996 	if (size)
997 		*size = result1 + result2 + result3;
998 
999 	return B_OK;
1000 }
1001 
1002 
1003 /*	The concept of message sending by area:
1004 
1005 	The traditional way of sending a message is to send it by flattening it to
1006 	a buffer, pushing it through a port, reading it into the outputbuffer and
1007 	unflattening it from there (copying the data again). While this works ok
1008 	for small messages it does not make any sense for larger ones and may even
1009 	hit some port capacity limit.
1010 	Often in the life of a BMessage, it will be sent to someone. Almost as
1011 	often the one receiving the message will not need to change the message
1012 	in any way, but uses it "read only" to get information from it. This means
1013 	that all that copying is pretty pointless in the first place since we
1014 	could simply pass the original buffers on.
1015 	It's obviously not exactly as simple as this, since we cannot just use the
1016 	memory of one application in another - but we can share areas with
1017 	eachother.
1018 	Therefore instead of flattening into a buffer, we copy the message data
1019 	into an area, put this information into the message header and only push
1020 	this through the port. The receiving looper then builds a BMessage from
1021 	the header, that only references the data in the area (not copying it),
1022 	allowing read only access to it.
1023 	Only if write access is necessary the message will be copyed from the area
1024 	to its own buffers (like in the unflatten step before).
1025 	The double copying is reduced to a single copy in most cases and we safe
1026 	the slower route of moving the data through a port.
1027 	Additionally we save us the reference counting with the use of areas that
1028 	are reference counted internally. So we don't have to worry about leaving
1029 	an area behind or deleting one that is still in use.
1030 */
1031 
1032 status_t
1033 BMessage::_FlattenToArea(message_header **_header) const
1034 {
1035 	DEBUG_FUNCTION_ENTER;
1036 	message_header *header = (message_header *)malloc(sizeof(message_header));
1037 	if (header == NULL)
1038 		return B_NO_MEMORY;
1039 
1040 	memcpy(header, fHeader, sizeof(message_header));
1041 
1042 	header->what = what;
1043 	header->message_area = -1;
1044 	*_header = header;
1045 
1046 	if (header->field_count == 0 && header->data_size == 0)
1047 		return B_OK;
1048 
1049 	char *address = NULL;
1050 	size_t fieldsSize = header->field_count * sizeof(field_header);
1051 	size_t size = fieldsSize + header->data_size;
1052 	size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
1053 	area_id area = create_area("BMessage data", (void **)&address,
1054 		B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1055 
1056 	if (area < 0) {
1057 		free(header);
1058 		*_header = NULL;
1059 		return area;
1060 	}
1061 
1062 	memcpy(address, fFields, fieldsSize);
1063 	memcpy(address + fieldsSize, fData, fHeader->data_size);
1064 	header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
1065 	header->message_area = area;
1066 	return B_OK;
1067 }
1068 
1069 
1070 status_t
1071 BMessage::_Reference()
1072 {
1073 	DEBUG_FUNCTION_ENTER;
1074 	fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA;
1075 
1076 	/* if there is no data at all we don't need the area */
1077 	if (fHeader->field_count == 0 && fHeader->data_size == 0)
1078 		return B_OK;
1079 
1080 	area_info areaInfo;
1081 	status_t result = get_area_info(fHeader->message_area, &areaInfo);
1082 	if (result < B_OK)
1083 		return result;
1084 
1085 	uint8 *address = (uint8 *)areaInfo.address;
1086 
1087 	fFields = (field_header *)address;
1088 	fData = address + fHeader->field_count * sizeof(field_header);
1089 	return B_OK;
1090 }
1091 
1092 
1093 status_t
1094 BMessage::_Dereference()
1095 {
1096 	DEBUG_FUNCTION_ENTER;
1097 	delete_area(fHeader->message_area);
1098 	fHeader->message_area = -1;
1099 	fFields = NULL;
1100 	fData = NULL;
1101 	return B_OK;
1102 }
1103 
1104 
1105 status_t
1106 BMessage::_CopyForWrite()
1107 {
1108 	DEBUG_FUNCTION_ENTER;
1109 
1110 	field_header *newFields = NULL;
1111 	uint8 *newData = NULL;
1112 
1113 	if (fHeader->field_count > 0) {
1114 		size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1115 		newFields = (field_header *)malloc(fieldsSize);
1116 		if (newFields == NULL)
1117 			return B_NO_MEMORY;
1118 
1119 		memcpy(newFields, fFields, fieldsSize);
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 	fFieldsAvailable = 0;
1135 	fDataAvailable = 0;
1136 
1137 	fFields = newFields;
1138 	fData = newData;
1139 	return B_OK;
1140 }
1141 
1142 
1143 status_t
1144 BMessage::_ValidateMessage()
1145 {
1146 	if (fHeader->field_count == 0)
1147 		return B_OK;
1148 
1149 	if (fFields == NULL)
1150 		return B_NO_INIT;
1151 
1152 	for (uint32 i = 0; i < fHeader->field_count; i++) {
1153 		field_header *field = &fFields[i];
1154 		if ((field->next_field >= 0
1155 				&& (uint32)field->next_field > fHeader->field_count)
1156 			|| (field->offset + field->name_length + field->data_size
1157 				> fHeader->data_size)) {
1158 			// the message is corrupt
1159 			MakeEmpty();
1160 			return B_BAD_VALUE;
1161 		}
1162 	}
1163 
1164 	return B_OK;
1165 }
1166 
1167 
1168 status_t
1169 BMessage::Unflatten(const char *flatBuffer)
1170 {
1171 	DEBUG_FUNCTION_ENTER;
1172 	if (flatBuffer == NULL)
1173 		return B_BAD_VALUE;
1174 
1175 	uint32 format = *(uint32 *)flatBuffer;
1176 	if (format != MESSAGE_FORMAT_HAIKU)
1177 		return BPrivate::MessageAdapter::Unflatten(format, this, flatBuffer);
1178 
1179 	// native message unflattening
1180 
1181 	_Clear();
1182 
1183 	fHeader = (message_header *)malloc(sizeof(message_header));
1184 	if (fHeader == NULL)
1185 		return B_NO_MEMORY;
1186 
1187 	memcpy(fHeader, flatBuffer, sizeof(message_header));
1188 	flatBuffer += sizeof(message_header);
1189 
1190 	if (fHeader->format != MESSAGE_FORMAT_HAIKU
1191 		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
1192 		_InitHeader();
1193 		return B_BAD_VALUE;
1194 	}
1195 
1196 	what = fHeader->what;
1197 
1198 	if ((fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) != 0
1199 		&& fHeader->message_area >= 0) {
1200 		status_t result = _Reference();
1201 		if (result != B_OK)
1202 			return result;
1203 	} else {
1204 		fHeader->message_area = -1;
1205 
1206 		if (fHeader->field_count > 0) {
1207 			size_t fieldsSize = fHeader->field_count * sizeof(field_header);
1208 			fFields = (field_header *)malloc(fieldsSize);
1209 			if (fFields == NULL) {
1210 				_InitHeader();
1211 				return B_NO_MEMORY;
1212 			}
1213 
1214 			memcpy(fFields, flatBuffer, fieldsSize);
1215 			flatBuffer += fieldsSize;
1216 		}
1217 
1218 		if (fHeader->data_size > 0) {
1219 			fData = (uint8 *)malloc(fHeader->data_size);
1220 			if (fData == NULL) {
1221 				free(fFields);
1222 				fFields = NULL;
1223 				_InitHeader();
1224 				return B_NO_MEMORY;
1225 			}
1226 
1227 			memcpy(fData, flatBuffer, fHeader->data_size);
1228 		}
1229 	}
1230 
1231 	return _ValidateMessage();
1232 }
1233 
1234 
1235 status_t
1236 BMessage::Unflatten(BDataIO *stream)
1237 {
1238 	DEBUG_FUNCTION_ENTER;
1239 	if (stream == NULL)
1240 		return B_BAD_VALUE;
1241 
1242 	uint32 format = 0;
1243 	stream->Read(&format, sizeof(uint32));
1244 	if (format != MESSAGE_FORMAT_HAIKU)
1245 		return BPrivate::MessageAdapter::Unflatten(format, this, stream);
1246 
1247 	// native message unflattening
1248 
1249 	_Clear();
1250 
1251 	fHeader = (message_header *)malloc(sizeof(message_header));
1252 	if (fHeader == NULL)
1253 		return B_NO_MEMORY;
1254 
1255 	fHeader->format = format;
1256 	uint8 *header = (uint8 *)fHeader;
1257 	ssize_t result = stream->Read(header + sizeof(uint32),
1258 		sizeof(message_header) - sizeof(uint32));
1259 	if (result != sizeof(message_header) - sizeof(uint32)
1260 		|| (fHeader->flags & MESSAGE_FLAG_VALID) == 0) {
1261 		_InitHeader();
1262 		return result < 0 ? result : B_BAD_VALUE;
1263 	}
1264 
1265 	what = fHeader->what;
1266 
1267 	fHeader->message_area = -1;
1268 
1269 	if (fHeader->field_count > 0) {
1270 		ssize_t fieldsSize = fHeader->field_count * sizeof(field_header);
1271 		fFields = (field_header *)malloc(fieldsSize);
1272 		if (fFields == NULL) {
1273 			_InitHeader();
1274 			return B_NO_MEMORY;
1275 		}
1276 
1277 		result = stream->Read(fFields, fieldsSize);
1278 		if (result != fieldsSize)
1279 			return result < 0 ? result : B_BAD_VALUE;
1280 	}
1281 
1282 	if (fHeader->data_size > 0) {
1283 		fData = (uint8 *)malloc(fHeader->data_size);
1284 		if (fData == NULL) {
1285 			free(fFields);
1286 			fFields = NULL;
1287 			_InitHeader();
1288 			return B_NO_MEMORY;
1289 		}
1290 
1291 		result = stream->Read(fData, fHeader->data_size);
1292 		if (result != (ssize_t)fHeader->data_size)
1293 			return result < 0 ? result : B_BAD_VALUE;
1294 	}
1295 
1296 	return _ValidateMessage();
1297 }
1298 
1299 
1300 status_t
1301 BMessage::AddSpecifier(const char *property)
1302 {
1303 	DEBUG_FUNCTION_ENTER;
1304 	BMessage message(B_DIRECT_SPECIFIER);
1305 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1306 	if (result < B_OK)
1307 		return result;
1308 
1309 	return AddSpecifier(&message);
1310 }
1311 
1312 
1313 status_t
1314 BMessage::AddSpecifier(const char *property, int32 index)
1315 {
1316 	DEBUG_FUNCTION_ENTER;
1317 	BMessage message(B_INDEX_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 	return AddSpecifier(&message);
1327 }
1328 
1329 
1330 status_t
1331 BMessage::AddSpecifier(const char *property, int32 index, int32 range)
1332 {
1333 	DEBUG_FUNCTION_ENTER;
1334 	if (range < 0)
1335 		return B_BAD_VALUE;
1336 
1337 	BMessage message(B_RANGE_SPECIFIER);
1338 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1339 	if (result < B_OK)
1340 		return result;
1341 
1342 	result = message.AddInt32("index", index);
1343 	if (result < B_OK)
1344 		return result;
1345 
1346 	result = message.AddInt32("range", range);
1347 	if (result < B_OK)
1348 		return result;
1349 
1350 	return AddSpecifier(&message);
1351 }
1352 
1353 
1354 status_t
1355 BMessage::AddSpecifier(const char *property, const char *name)
1356 {
1357 	DEBUG_FUNCTION_ENTER;
1358 	BMessage message(B_NAME_SPECIFIER);
1359 	status_t result = message.AddString(B_PROPERTY_ENTRY, property);
1360 	if (result < B_OK)
1361 		return result;
1362 
1363 	result = message.AddString(B_PROPERTY_NAME_ENTRY, name);
1364 	if (result < B_OK)
1365 		return result;
1366 
1367 	return AddSpecifier(&message);
1368 }
1369 
1370 
1371 status_t
1372 BMessage::AddSpecifier(const BMessage *specifier)
1373 {
1374 	DEBUG_FUNCTION_ENTER;
1375 	status_t result = AddMessage(B_SPECIFIER_ENTRY, specifier);
1376 	if (result < B_OK)
1377 		return result;
1378 
1379 	fHeader->current_specifier++;
1380 	fHeader->flags |= MESSAGE_FLAG_HAS_SPECIFIERS;
1381 	return B_OK;
1382 }
1383 
1384 
1385 status_t
1386 BMessage::SetCurrentSpecifier(int32 index)
1387 {
1388 	DEBUG_FUNCTION_ENTER;
1389 	if (index < 0)
1390 		return B_BAD_INDEX;
1391 
1392 	type_code type;
1393 	int32 count;
1394 	status_t result = GetInfo(B_SPECIFIER_ENTRY, &type, &count);
1395 	if (result < B_OK)
1396 		return result;
1397 
1398 	if (index > count)
1399 		return B_BAD_INDEX;
1400 
1401 	fHeader->current_specifier = index;
1402 	return B_OK;
1403 }
1404 
1405 
1406 status_t
1407 BMessage::GetCurrentSpecifier(int32 *index, BMessage *specifier, int32 *_what,
1408 	const char **property) const
1409 {
1410 	DEBUG_FUNCTION_ENTER;
1411 
1412 	if (index != NULL)
1413 		*index = fHeader->current_specifier;
1414 
1415 	if (fHeader->current_specifier < 0
1416 		|| (fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1417 		return B_BAD_SCRIPT_SYNTAX;
1418 
1419 	if (specifier) {
1420 		if (FindMessage(B_SPECIFIER_ENTRY, fHeader->current_specifier,
1421 			specifier) < B_OK)
1422 			return B_BAD_SCRIPT_SYNTAX;
1423 
1424 		if (_what != NULL)
1425 			*_what = specifier->what;
1426 
1427 		if (property) {
1428 			if (specifier->FindString(B_PROPERTY_ENTRY, property) < B_OK)
1429 				return B_BAD_SCRIPT_SYNTAX;
1430 		}
1431 	}
1432 
1433 	return B_OK;
1434 }
1435 
1436 
1437 bool
1438 BMessage::HasSpecifiers() const
1439 {
1440 	DEBUG_FUNCTION_ENTER;
1441 	return (fHeader->flags & MESSAGE_FLAG_HAS_SPECIFIERS) != 0;
1442 }
1443 
1444 
1445 status_t
1446 BMessage::PopSpecifier()
1447 {
1448 	DEBUG_FUNCTION_ENTER;
1449 	if (fHeader->current_specifier < 0 ||
1450 		(fHeader->flags & MESSAGE_FLAG_WAS_DELIVERED) == 0)
1451 		return B_BAD_VALUE;
1452 
1453 	if (fHeader->current_specifier >= 0)
1454 		fHeader->current_specifier--;
1455 
1456 	return B_OK;
1457 }
1458 
1459 
1460 status_t
1461 BMessage::_ResizeData(uint32 offset, int32 change)
1462 {
1463 	if (change == 0)
1464 		return B_OK;
1465 
1466 	/* optimize for the most usual case: appending data */
1467 	if (offset < fHeader->data_size) {
1468 		field_header *field = fFields;
1469 		for (uint32 i = 0; i < fHeader->field_count; i++, field++) {
1470 			if (field->offset >= offset)
1471 				field->offset += change;
1472 		}
1473 	}
1474 
1475 	if (change > 0) {
1476 		if (fDataAvailable >= (uint32)change) {
1477 			if (offset < fHeader->data_size) {
1478 				memmove(fData + offset + change, fData + offset,
1479 					fHeader->data_size - offset);
1480 			}
1481 
1482 			fDataAvailable -= change;
1483 			fHeader->data_size += change;
1484 			return B_OK;
1485 		}
1486 
1487 		size_t size = fHeader->data_size * 2;
1488 		size = min_c(size, fHeader->data_size + MAX_DATA_PREALLOCATION);
1489 		size = max_c(size, fHeader->data_size + change);
1490 
1491 		uint8 *newData = (uint8 *)realloc(fData, size);
1492 		if (size > 0 && newData == NULL)
1493 			return B_NO_MEMORY;
1494 
1495 		fData = newData;
1496 		if (offset < fHeader->data_size) {
1497 			memmove(fData + offset + change, fData + offset,
1498 				fHeader->data_size - offset);
1499 		}
1500 
1501 		fHeader->data_size += change;
1502 		fDataAvailable = size - fHeader->data_size;
1503 	} else {
1504 		ssize_t length = fHeader->data_size - offset + change;
1505 		if (length > 0)
1506 			memmove(fData + offset, fData + offset - change, length);
1507 
1508 		// change is negative
1509 		fHeader->data_size += change;
1510 		fDataAvailable -= change;
1511 
1512 		if (fDataAvailable > MAX_DATA_PREALLOCATION) {
1513 			ssize_t available = MAX_DATA_PREALLOCATION / 2;
1514 			ssize_t size = fHeader->data_size + available;
1515 			uint8 *newData = (uint8 *)realloc(fData, size);
1516 			if (size > 0 && newData == NULL) {
1517 				// this is strange, but not really fatal
1518 				return B_OK;
1519 			}
1520 
1521 			fData = newData;
1522 			fDataAvailable = available;
1523 		}
1524 	}
1525 
1526 	return B_OK;
1527 }
1528 
1529 
1530 uint32
1531 BMessage::_HashName(const char *name) const
1532 {
1533 	char ch;
1534 	uint32 result = 0;
1535 
1536 	while ((ch = *name++) != 0) {
1537 		result = (result << 7) ^ (result >> 24);
1538 		result ^= ch;
1539 	}
1540 
1541 	result ^= result << 12;
1542 	return result;
1543 }
1544 
1545 
1546 status_t
1547 BMessage::_FindField(const char *name, type_code type, field_header **result) const
1548 {
1549 	if (name == NULL)
1550 		return B_BAD_VALUE;
1551 
1552 	if (fHeader == NULL || fFields == NULL || fData == NULL)
1553 		return B_NAME_NOT_FOUND;
1554 
1555 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1556 	int32 nextField = fHeader->hash_table[hash];
1557 
1558 	while (nextField >= 0) {
1559 		field_header *field = &fFields[nextField];
1560 		if ((field->flags & FIELD_FLAG_VALID) == 0)
1561 			break;
1562 
1563 		if (strncmp((const char *)(fData + field->offset), name,
1564 			field->name_length) == 0) {
1565 			if (type != B_ANY_TYPE && field->type != type)
1566 				return B_BAD_TYPE;
1567 
1568 			*result = field;
1569 			return B_OK;
1570 		}
1571 
1572 		nextField = field->next_field;
1573 	}
1574 
1575 	return B_NAME_NOT_FOUND;
1576 }
1577 
1578 
1579 status_t
1580 BMessage::_AddField(const char *name, type_code type, bool isFixedSize,
1581 	field_header **result)
1582 {
1583 	if (fHeader == NULL)
1584 		return B_ERROR;
1585 
1586 	if (fFieldsAvailable <= 0) {
1587 		uint32 count = fHeader->field_count * 2 + 1;
1588 		count = min_c(count, fHeader->field_count + MAX_FIELD_PREALLOCATION);
1589 
1590 		field_header *newFields = (field_header *)realloc(fFields,
1591 			count * sizeof(field_header));
1592 		if (count > 0 && newFields == NULL)
1593 			return B_NO_MEMORY;
1594 
1595 		fFields = newFields;
1596 		fFieldsAvailable = count - fHeader->field_count;
1597 	}
1598 
1599 	uint32 hash = _HashName(name) % fHeader->hash_table_size;
1600 	int32 *nextField = &fHeader->hash_table[hash];
1601 	while (*nextField >= 0)
1602 		nextField = &fFields[*nextField].next_field;
1603 	*nextField = fHeader->field_count;
1604 
1605 	field_header *field = &fFields[fHeader->field_count];
1606 	field->type = type;
1607 	field->count = 0;
1608 	field->data_size = 0;
1609 	field->next_field = -1;
1610 	field->offset = fHeader->data_size;
1611 	field->name_length = strlen(name) + 1;
1612 	status_t status = _ResizeData(field->offset, field->name_length);
1613 	if (status < B_OK)
1614 		return status;
1615 
1616 	memcpy(fData + field->offset, name, field->name_length);
1617 	field->flags = FIELD_FLAG_VALID;
1618 	if (isFixedSize)
1619 		field->flags |= FIELD_FLAG_FIXED_SIZE;
1620 
1621 	fFieldsAvailable--;
1622 	fHeader->field_count++;
1623 	*result = field;
1624 	return B_OK;
1625 }
1626 
1627 
1628 status_t
1629 BMessage::_RemoveField(field_header *field)
1630 {
1631 	status_t result = _ResizeData(field->offset, -(field->data_size
1632 		+ field->name_length));
1633 	if (result < B_OK)
1634 		return result;
1635 
1636 	int32 index = ((uint8 *)field - (uint8 *)fFields) / sizeof(field_header);
1637 	int32 nextField = field->next_field;
1638 	if (nextField > index)
1639 		nextField--;
1640 
1641 	int32 *value = fHeader->hash_table;
1642 	for (uint32 i = 0; i < fHeader->hash_table_size; i++, value++) {
1643 		if (*value > index)
1644 			*value -= 1;
1645 		else if (*value == index)
1646 			*value = nextField;
1647 	}
1648 
1649 	field_header *other = fFields;
1650 	for (uint32 i = 0; i < fHeader->field_count; i++, other++) {
1651 		if (other->next_field > index)
1652 			other->next_field--;
1653 		else if (other->next_field == index)
1654 			other->next_field = nextField;
1655 	}
1656 
1657 	size_t size = (fHeader->field_count - index - 1) * sizeof(field_header);
1658 	memmove(fFields + index, fFields + index + 1, size);
1659 	fHeader->field_count--;
1660 	fFieldsAvailable++;
1661 
1662 	if (fFieldsAvailable > MAX_FIELD_PREALLOCATION) {
1663 		ssize_t available = MAX_FIELD_PREALLOCATION / 2;
1664 		size = (fHeader->field_count + available) * sizeof(field_header);
1665 		field_header *newFields = (field_header *)realloc(fFields, size);
1666 		if (size > 0 && newFields == NULL) {
1667 			// this is strange, but not really fatal
1668 			return B_OK;
1669 		}
1670 
1671 		fFields = newFields;
1672 		fFieldsAvailable = available;
1673 	}
1674 
1675 	return B_OK;
1676 }
1677 
1678 
1679 status_t
1680 BMessage::AddData(const char *name, type_code type, const void *data,
1681 	ssize_t numBytes, bool isFixedSize, int32 count)
1682 {
1683 	// Note that the "count" argument is only a hint at how many items
1684 	// the caller expects to add to this field. Since we do no item pre-
1685 	// allocation, we ignore this argument.
1686 	DEBUG_FUNCTION_ENTER;
1687 	if (numBytes <= 0 || data == NULL)
1688 		return B_BAD_VALUE;
1689 
1690 	if (fHeader->message_area >= 0)
1691 		_CopyForWrite();
1692 
1693 	field_header *field = NULL;
1694 	status_t result = _FindField(name, type, &field);
1695 	if (result == B_NAME_NOT_FOUND)
1696 		result = _AddField(name, type, isFixedSize, &field);
1697 
1698 	if (result < B_OK)
1699 		return result;
1700 
1701 	if (field == NULL)
1702 		return B_ERROR;
1703 
1704 	uint32 offset = field->offset + field->name_length + field->data_size;
1705 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1706 		if (field->count) {
1707 			ssize_t size = field->data_size / field->count;
1708 			if (size != numBytes)
1709 				return B_BAD_VALUE;
1710 		}
1711 
1712 		result = _ResizeData(offset, numBytes);
1713 		if (result < B_OK) {
1714 			if (field->count == 0)
1715 				_RemoveField(field);
1716 			return result;
1717 		}
1718 
1719 		memcpy(fData + offset, data, numBytes);
1720 		field->data_size += numBytes;
1721 	} else {
1722 		int32 change = numBytes + sizeof(uint32);
1723 		result = _ResizeData(offset, change);
1724 		if (result < B_OK) {
1725 			if (field->count == 0)
1726 				_RemoveField(field);
1727 			return result;
1728 		}
1729 
1730 		uint32 size = (uint32)numBytes;
1731 		memcpy(fData + offset, &size, sizeof(uint32));
1732 		memcpy(fData + offset + sizeof(uint32), data, size);
1733 		field->data_size += change;
1734 	}
1735 
1736 	field->count++;
1737 	return B_OK;
1738 }
1739 
1740 
1741 status_t
1742 BMessage::RemoveData(const char *name, int32 index)
1743 {
1744 	DEBUG_FUNCTION_ENTER;
1745 	if (index < 0)
1746 		return B_BAD_INDEX;
1747 
1748 	if (fHeader->message_area >= 0)
1749 		_CopyForWrite();
1750 
1751 	field_header *field = NULL;
1752 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1753 
1754 	if (result < B_OK)
1755 		return result;
1756 
1757 	if (field == NULL)
1758 		return B_ERROR;
1759 
1760 	if ((uint32)index >= field->count)
1761 		return B_BAD_INDEX;
1762 
1763 	if (field->count == 1)
1764 		return _RemoveField(field);
1765 
1766 	uint32 offset = field->offset + field->name_length;
1767 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1768 		ssize_t size = field->data_size / field->count;
1769 		result = _ResizeData(offset + index * size, -size);
1770 		if (result < B_OK)
1771 			return result;
1772 
1773 		field->data_size -= size;
1774 	} else {
1775 		uint8 *pointer = fData + offset;
1776 		for (int32 i = 0; i < index; i++) {
1777 			offset += *(uint32 *)pointer + sizeof(uint32);
1778 			pointer = fData + offset;
1779 		}
1780 
1781 		size_t currentSize = *(uint32 *)pointer + sizeof(uint32);
1782 		result = _ResizeData(offset, -currentSize);
1783 		if (result < B_OK)
1784 			return result;
1785 
1786 		field->data_size -= currentSize;
1787 	}
1788 
1789 	field->count--;
1790 	return B_OK;
1791 }
1792 
1793 
1794 status_t
1795 BMessage::RemoveName(const char *name)
1796 {
1797 	DEBUG_FUNCTION_ENTER;
1798 	if (fHeader->message_area >= 0)
1799 		_CopyForWrite();
1800 
1801 	field_header *field = NULL;
1802 	status_t result = _FindField(name, B_ANY_TYPE, &field);
1803 
1804 	if (result < B_OK)
1805 		return result;
1806 
1807 	if (field == NULL)
1808 		return B_ERROR;
1809 
1810 	return _RemoveField(field);
1811 }
1812 
1813 
1814 status_t
1815 BMessage::MakeEmpty()
1816 {
1817 	DEBUG_FUNCTION_ENTER;
1818 	_Clear();
1819 	_InitHeader();
1820 	return B_OK;
1821 }
1822 
1823 
1824 status_t
1825 BMessage::FindData(const char *name, type_code type, int32 index,
1826 	const void **data, ssize_t *numBytes) const
1827 {
1828 	DEBUG_FUNCTION_ENTER;
1829 	if (data == NULL)
1830 		return B_BAD_VALUE;
1831 
1832 	*data = NULL;
1833 	field_header *field = NULL;
1834 	status_t result = _FindField(name, type, &field);
1835 
1836 	if (result < B_OK)
1837 		return result;
1838 
1839 	if (field == NULL)
1840 		return B_ERROR;
1841 
1842 	if (index < 0 || (uint32)index >= field->count)
1843 		return B_BAD_INDEX;
1844 
1845 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1846 		size_t bytes = field->data_size / field->count;
1847 		*data = fData + field->offset + field->name_length + index * bytes;
1848 		if (numBytes != NULL)
1849 			*numBytes = bytes;
1850 	} else {
1851 		uint8 *pointer = fData + field->offset + field->name_length;
1852 		for (int32 i = 0; i < index; i++)
1853 			pointer += *(uint32 *)pointer + sizeof(uint32);
1854 
1855 		*data = pointer + sizeof(uint32);
1856 		if (numBytes != NULL)
1857 			*numBytes = *(uint32 *)pointer;
1858 	}
1859 
1860 	return B_OK;
1861 }
1862 
1863 
1864 status_t
1865 BMessage::ReplaceData(const char *name, type_code type, int32 index,
1866 	const void *data, ssize_t numBytes)
1867 {
1868 	DEBUG_FUNCTION_ENTER;
1869 	if (numBytes <= 0 || data == NULL)
1870 		return B_BAD_VALUE;
1871 
1872 	field_header *field = NULL;
1873 	status_t result = _FindField(name, type, &field);
1874 
1875 	if (result < B_OK)
1876 		return result;
1877 
1878 	if (field == NULL)
1879 		return B_ERROR;
1880 
1881 	if (index < 0 || (uint32)index >= field->count)
1882 		return B_BAD_INDEX;
1883 
1884 	if (fHeader->message_area >= 0)
1885 		_CopyForWrite();
1886 
1887 	if ((field->flags & FIELD_FLAG_FIXED_SIZE) != 0) {
1888 		ssize_t size = field->data_size / field->count;
1889 		if (size != numBytes)
1890 			return B_BAD_VALUE;
1891 
1892 		memcpy(fData + field->offset + field->name_length + index * size, data,
1893 			size);
1894 	} else {
1895 		uint32 offset = field->offset + field->name_length;
1896 		uint8 *pointer = fData + offset;
1897 
1898 		for (int32 i = 0; i < index; i++) {
1899 			offset += *(uint32 *)pointer + sizeof(uint32);
1900 			pointer = fData + offset;
1901 		}
1902 
1903 		size_t currentSize = *(uint32 *)pointer;
1904 		int32 change = numBytes - currentSize;
1905 		result = _ResizeData(offset, change);
1906 		if (result < B_OK)
1907 			return result;
1908 
1909 		uint32 newSize = (uint32)numBytes;
1910 		memcpy(fData + offset, &newSize, sizeof(uint32));
1911 		memcpy(fData + offset + sizeof(uint32), data, newSize);
1912 		field->data_size += change;
1913 	}
1914 
1915 	return B_OK;
1916 }
1917 
1918 
1919 bool
1920 BMessage::HasData(const char *name, type_code type, int32 index) const
1921 {
1922 	DEBUG_FUNCTION_ENTER;
1923 	field_header *field = NULL;
1924 	status_t result = _FindField(name, type, &field);
1925 
1926 	if (result < B_OK)
1927 		return false;
1928 
1929 	if (field == NULL)
1930 		return false;
1931 
1932 	if (index < 0 || (uint32)index >= field->count)
1933 		return false;
1934 
1935 	return true;
1936 }
1937 
1938 
1939 /* Static functions for cache initialization and cleanup */
1940 void
1941 BMessage::_StaticInit()
1942 {
1943 	DEBUG_FUNCTION_ENTER2;
1944 	sReplyPorts[0] = create_port(1, "tmp_rport0");
1945 	sReplyPorts[1] = create_port(1, "tmp_rport1");
1946 	sReplyPorts[2] = create_port(1, "tmp_rport2");
1947 
1948 	sReplyPortInUse[0] = 0;
1949 	sReplyPortInUse[1] = 0;
1950 	sReplyPortInUse[2] = 0;
1951 
1952 	sMsgCache = new BBlockCache(20, sizeof(BMessage), B_OBJECT_CACHE);
1953 }
1954 
1955 
1956 void
1957 BMessage::_StaticReInitForkedChild()
1958 {
1959 	DEBUG_FUNCTION_ENTER2;
1960 
1961 	// overwrite the inherited ports with a set of our own
1962 	sReplyPorts[0] = create_port(1, "tmp_rport0");
1963 	sReplyPorts[1] = create_port(1, "tmp_rport1");
1964 	sReplyPorts[2] = create_port(1, "tmp_rport2");
1965 
1966 	sReplyPortInUse[0] = 0;
1967 	sReplyPortInUse[1] = 0;
1968 	sReplyPortInUse[2] = 0;
1969 }
1970 
1971 
1972 void
1973 BMessage::_StaticCleanup()
1974 {
1975 	DEBUG_FUNCTION_ENTER2;
1976 	delete_port(sReplyPorts[0]);
1977 	sReplyPorts[0] = -1;
1978 	delete_port(sReplyPorts[1]);
1979 	sReplyPorts[1] = -1;
1980 	delete_port(sReplyPorts[2]);
1981 	sReplyPorts[2] = -1;
1982 }
1983 
1984 
1985 void
1986 BMessage::_StaticCacheCleanup()
1987 {
1988 	DEBUG_FUNCTION_ENTER2;
1989 	delete sMsgCache;
1990 	sMsgCache = NULL;
1991 }
1992 
1993 
1994 int32
1995 BMessage::_StaticGetCachedReplyPort()
1996 {
1997 	DEBUG_FUNCTION_ENTER2;
1998 	int index = -1;
1999 	for (int32 i = 0; i < sNumReplyPorts; i++) {
2000 		int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
2001 		if (old == 0) {
2002 			// This entry is free
2003 			index = i;
2004 			break;
2005 		} else {
2006 			// This entry is being used.
2007 			atomic_add(&(sReplyPortInUse[i]), -1);
2008 		}
2009 	}
2010 
2011 	return index;
2012 }
2013 
2014 
2015 status_t
2016 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2017 	bigtime_t timeout, bool replyRequired, BMessenger &replyTo) const
2018 {
2019 	DEBUG_FUNCTION_ENTER;
2020 	ssize_t size = 0;
2021 	char *buffer = NULL;
2022 	message_header *header = NULL;
2023 	status_t result = B_OK;
2024 
2025 	BPrivate::BDirectMessageTarget* direct = NULL;
2026 	BMessage* copy = NULL;
2027 	if (portOwner == BPrivate::current_team())
2028 		BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
2029 
2030 	if (direct != NULL) {
2031 		// We have a direct local message target - we can just enqueue the message
2032 		// in its message queue. This will also prevent possible deadlocks when the
2033 		// queue is full.
2034 		copy = new BMessage(*this);
2035 		if (copy != NULL) {
2036 			header = copy->fHeader;
2037 			header->flags = fHeader->flags;
2038 		} else {
2039 			direct->Release();
2040 			return B_NO_MEMORY;
2041 		}
2042 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2043 	} else if (fHeader->data_size > B_PAGE_SIZE * 10) {
2044 		// ToDo: bind the above size to the max port message size
2045 		// use message passing by area for such a large message
2046 		result = _FlattenToArea(&header);
2047 		if (result != B_OK)
2048 			return result;
2049 
2050 		buffer = (char *)header;
2051 		size = sizeof(message_header);
2052 
2053 		if (header->message_area >= 0) {
2054 			team_id target = portOwner;
2055 			if (target < 0) {
2056 				port_info info;
2057 				result = get_port_info(port, &info);
2058 				if (result != B_OK) {
2059 					free(header);
2060 					return result;
2061 				}
2062 				target = info.team;
2063 			}
2064 
2065 			void *address = NULL;
2066 			area_id transfered = _kern_transfer_area(header->message_area,
2067 				&address, B_ANY_ADDRESS, target);
2068 			if (transfered < 0) {
2069 				delete_area(header->message_area);
2070 				free(header);
2071 				return transfered;
2072 			}
2073 
2074 			header->message_area = transfered;
2075 		}
2076 #endif
2077 	} else {
2078 		size = FlattenedSize();
2079 		buffer = (char *)malloc(size);
2080 		if (buffer == NULL)
2081 			return B_NO_MEMORY;
2082 
2083 		result = Flatten(buffer, size);
2084 		if (result < B_OK) {
2085 			free(buffer);
2086 			return result;
2087 		}
2088 
2089 		header = (message_header *)buffer;
2090 	}
2091 
2092 	if (!replyTo.IsValid()) {
2093 		BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
2094 			fHeader->reply_port, fHeader->reply_target);
2095 
2096 		if (!replyTo.IsValid())
2097 			replyTo = be_app_messenger;
2098 	}
2099 
2100 	BMessenger::Private replyToPrivate(replyTo);
2101 
2102 	if (replyRequired) {
2103 		header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
2104 		header->flags &= ~MESSAGE_FLAG_REPLY_DONE;
2105 	}
2106 
2107 	header->target = token;
2108 	header->reply_team = replyToPrivate.Team();
2109 	header->reply_port = replyToPrivate.Port();
2110 	header->reply_target = replyToPrivate.Token();
2111 	header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2112 
2113 	if (direct == NULL) {
2114 		KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, "
2115 			"message: '%c%c%c%c'", portOwner, port, token,
2116 			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2117 
2118 		do {
2119 			result = write_port_etc(port, kPortMessageCode, (void *)buffer,
2120 				size, B_RELATIVE_TIMEOUT, timeout);
2121 		} while (result == B_INTERRUPTED);
2122 	}
2123 
2124 	if (result == B_OK && IsSourceWaiting()) {
2125 		// the forwarded message will handle the reply - we must not do
2126 		// this anymore
2127 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
2128 	}
2129 
2130 	// we need to do this last because it is possible our
2131 	// message might be destroyed after it's enqueued in the
2132 	// target looper. Thus we don't want to do any ops that depend on
2133 	// members of this after the enqueue.
2134 	if (direct != NULL) {
2135 		KTRACE("BMessage send direct: port: %ld, token: %ld, "
2136 			"message: '%c%c%c%c'", port, token,
2137 			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2138 
2139 		// this is a local message transmission
2140 		direct->AddMessage(copy);
2141 		if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
2142 			// there is currently no message waiting, and we need to wakeup the looper
2143 			write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
2144 		}
2145 		direct->Release();
2146 	}
2147 
2148 	free(buffer);
2149 	return result;
2150 }
2151 
2152 
2153 /*!
2154 	Sends a message and waits synchronously for a reply.
2155 */
2156 status_t
2157 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2158 	BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
2159 {
2160 	if (IsSourceWaiting()) {
2161 		// we can't forward this message synchronously when it's already
2162 		// waiting for a reply
2163 		return B_ERROR;
2164 	}
2165 
2166 	DEBUG_FUNCTION_ENTER;
2167 	const int32 cachedReplyPort = _StaticGetCachedReplyPort();
2168 	port_id replyPort = B_BAD_PORT_ID;
2169 	status_t result = B_OK;
2170 
2171 	if (cachedReplyPort < B_OK) {
2172 		// All the cached reply ports are in use; create a new one
2173 		replyPort = create_port(1 /* for one message */, "tmp_reply_port");
2174 		if (replyPort < B_OK)
2175 			return replyPort;
2176 	} else {
2177 		assert(cachedReplyPort < sNumReplyPorts);
2178 		replyPort = sReplyPorts[cachedReplyPort];
2179 	}
2180 
2181 	team_id team = B_BAD_TEAM_ID;
2182 	if (be_app != NULL)
2183 		team = be_app->Team();
2184 	else {
2185 		port_info portInfo;
2186 		result = get_port_info(replyPort, &portInfo);
2187 		if (result < B_OK)
2188 			goto error;
2189 
2190 		team = portInfo.team;
2191 	}
2192 
2193 	result = set_port_owner(replyPort, portOwner);
2194 	if (result < B_OK)
2195 		goto error;
2196 
2197 	// tests if the queue of the reply port is really empty
2198 #if 0
2199 	port_info portInfo;
2200 	if (get_port_info(replyPort, &portInfo) == B_OK
2201 		&& portInfo.queue_count > 0) {
2202 		debugger("reply port not empty!");
2203 		printf("  reply port not empty! %ld message(s) in queue\n",
2204 			portInfo.queue_count);
2205 
2206 		// fetch and print the messages
2207 		for (int32 i = 0; i < portInfo.queue_count; i++) {
2208 			char buffer[1024];
2209 			int32 code;
2210 			ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer));
2211 			if (size < 0) {
2212 				printf("failed to read message from reply port\n");
2213 				continue;
2214 			}
2215 			if (size >= (ssize_t)sizeof(buffer)) {
2216 				printf("message from reply port too big\n");
2217 				continue;
2218 			}
2219 
2220 			BMemoryIO stream(buffer, size);
2221 			BMessage reply;
2222 			if (reply.Unflatten(&stream) != B_OK) {
2223 				printf("failed to unflatten message from reply port\n");
2224 				continue;
2225 			}
2226 
2227 			printf("message %ld from reply port:\n", i);
2228 			reply.PrintToStream();
2229 		}
2230 	}
2231 #endif
2232 
2233 	{
2234 		BMessenger replyTarget;
2235 		BMessenger::Private(replyTarget).SetTo(team, replyPort,
2236 			B_PREFERRED_TOKEN);
2237 		// TODO: replying could also use a BDirectMessageTarget like mechanism for local targets
2238 		result = _SendMessage(port, -1, token, sendTimeout, true,
2239 			replyTarget);
2240 	}
2241 
2242 	if (result < B_OK)
2243 		goto error;
2244 
2245 	int32 code;
2246 	result = handle_reply(replyPort, &code, replyTimeout, reply);
2247 	if (result < B_OK && cachedReplyPort >= 0) {
2248 		delete_port(replyPort);
2249 		sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
2250 	}
2251 
2252 error:
2253 	if (cachedReplyPort >= 0) {
2254 		// Reclaim ownership of cached port
2255 		set_port_owner(replyPort, team);
2256 		// Flag as available
2257 		atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
2258 		return result;
2259 	}
2260 
2261 	delete_port(replyPort);
2262 	return result;
2263 }
2264 
2265 
2266 status_t
2267 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
2268 	int32 token, bigtime_t timeout)
2269 {
2270 	DEBUG_FUNCTION_ENTER2;
2271 	if (data == NULL)
2272 		return B_BAD_VALUE;
2273 
2274 	uint32 magic = *(uint32 *)data;
2275 
2276 	if (magic == MESSAGE_FORMAT_HAIKU || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) {
2277 		message_header *header = (message_header *)data;
2278 		header->target = token;
2279 		header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2280 	} else if (magic == MESSAGE_FORMAT_R5) {
2281 		uint8 *header = (uint8 *)data;
2282 		header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
2283 			+ sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
2284 			+ sizeof(uint8) /* flags */;
2285 		*(int32 *)header = token;
2286 	} else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) {
2287 		KMessage::Header *header = (KMessage::Header *)data;
2288 		header->targetToken = token;
2289 	} else {
2290 		return B_NOT_A_MESSAGE;
2291 	}
2292 
2293 	// send the message
2294 	status_t result;
2295 
2296 	do {
2297 		result = write_port_etc(port, kPortMessageCode, data, size,
2298 			B_RELATIVE_TIMEOUT, timeout);
2299 	} while (result == B_INTERRUPTED);
2300 
2301 	return result;
2302 }
2303 
2304 
2305 void BMessage::_ReservedMessage1(void) {};
2306 void BMessage::_ReservedMessage2(void) {};
2307 void BMessage::_ReservedMessage3(void) {};
2308 
2309 
2310 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
2311 
2312 #define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
2313 status_t																	\
2314 BMessage::Add##typeName(const char *name, type val)							\
2315 {																			\
2316 	return AddData(name, typeCode, &val, sizeof(type), true);				\
2317 }																			\
2318 																			\
2319 status_t																	\
2320 BMessage::Find##typeName(const char *name, type *p) const					\
2321 {																			\
2322 	void *ptr = NULL;														\
2323 	ssize_t bytes = 0;														\
2324 	status_t error = B_OK;													\
2325 																			\
2326 	*p = type();															\
2327 	error = FindData(name, typeCode, 0, (const void **)&ptr, &bytes);		\
2328 																			\
2329 	if (error == B_OK)														\
2330 		memcpy(p, ptr, sizeof(type));										\
2331 																			\
2332 	return error;															\
2333 }																			\
2334 																			\
2335 status_t																	\
2336 BMessage::Find##typeName(const char *name, int32 index, type *p) const		\
2337 {																			\
2338 	void *ptr = NULL;														\
2339 	ssize_t bytes = 0;														\
2340 	status_t error = B_OK;													\
2341 																			\
2342 	*p = type();															\
2343 	error = FindData(name, typeCode, index, (const void **)&ptr, &bytes);	\
2344 																			\
2345 	if (error == B_OK)														\
2346 		memcpy(p, ptr, sizeof(type));										\
2347 																			\
2348 	return error;															\
2349 }																			\
2350 																			\
2351 status_t																	\
2352 BMessage::Replace##typeName(const char *name, type val)						\
2353 {																			\
2354 	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
2355 }																			\
2356 																			\
2357 status_t																	\
2358 BMessage::Replace##typeName(const char *name, int32 index, type val)		\
2359 {																			\
2360 	return ReplaceData(name, typeCode, index, &val, sizeof(type));			\
2361 }																			\
2362 																			\
2363 bool																		\
2364 BMessage::Has##typeName(const char *name, int32 index) const				\
2365 {																			\
2366 	return HasData(name, typeCode, index);									\
2367 }
2368 
2369 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2370 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2371 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2372 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2373 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2374 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2375 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2376 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2377 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2378 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2379 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2380 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2381 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2382 
2383 #undef DEFINE_FUNCTIONS
2384 
2385 #define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
2386 bool																		\
2387 BMessage::Has##typeName(const char *name, int32 index) const				\
2388 {																			\
2389 	return HasData(name, typeCode, index);									\
2390 }
2391 
2392 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2393 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2394 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2395 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2396 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2397 
2398 #undef DEFINE_HAS_FUNCTION
2399 
2400 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
2401 type																		\
2402 BMessage::Find##typeName(const char *name, int32 index) const				\
2403 {																			\
2404 	type val = initialize;													\
2405 	Find##typeName(name, index, &val);										\
2406 	return val;																\
2407 }
2408 
2409 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2410 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2411 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
2412 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2413 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2414 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2415 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2416 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2417 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2418 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2419 
2420 #undef DEFINE_LAZY_FIND_FUNCTION
2421 
2422 status_t
2423 BMessage::AddString(const char *name, const char *string)
2424 {
2425 	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false);
2426 }
2427 
2428 
2429 status_t
2430 BMessage::AddString(const char *name, const BString &string)
2431 {
2432 	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
2433 }
2434 
2435 
2436 status_t
2437 BMessage::AddPointer(const char *name, const void *pointer)
2438 {
2439 	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2440 }
2441 
2442 
2443 status_t
2444 BMessage::AddMessenger(const char *name, BMessenger messenger)
2445 {
2446 	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2447 }
2448 
2449 
2450 status_t
2451 BMessage::AddRef(const char *name, const entry_ref *ref)
2452 {
2453 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2454 	char buffer[size];
2455 
2456 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2457 
2458 	if (error >= B_OK)
2459 		error = AddData(name, B_REF_TYPE, buffer, size, false);
2460 
2461 	return error;
2462 }
2463 
2464 
2465 status_t
2466 BMessage::AddMessage(const char *name, const BMessage *message)
2467 {
2468 	if (message == NULL)
2469 		return B_BAD_VALUE;
2470 
2471 	// TODO: This and the following functions waste time by allocating and
2472 	// copying an extra buffer. Functions can be added that return a direct
2473 	// pointer into the message.
2474 
2475 	char stackBuffer[16384];
2476 	ssize_t size = message->FlattenedSize();
2477 
2478 	char* buffer;
2479 	if (size > (ssize_t)sizeof(stackBuffer)) {
2480 		buffer = (char *)malloc(size);
2481 		if (buffer == NULL)
2482 			return B_NO_MEMORY;
2483 	} else
2484 		buffer = stackBuffer;
2485 
2486 	status_t error = message->Flatten(buffer, size);
2487 
2488 	if (error >= B_OK)
2489 		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
2490 
2491 	if (buffer != stackBuffer)
2492 		free(buffer);
2493 
2494 	return error;
2495 }
2496 
2497 
2498 status_t
2499 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
2500 {
2501 	if (object == NULL)
2502 		return B_BAD_VALUE;
2503 
2504 	char stackBuffer[16384];
2505 	ssize_t size = object->FlattenedSize();
2506 
2507 	char* buffer;
2508 	if (size > (ssize_t)sizeof(stackBuffer)) {
2509 		buffer = (char *)malloc(size);
2510 		if (buffer == NULL)
2511 			return B_NO_MEMORY;
2512 	} else
2513 		buffer = stackBuffer;
2514 
2515 	status_t error = object->Flatten(buffer, size);
2516 
2517 	if (error >= B_OK)
2518 		error = AddData(name, object->TypeCode(), buffer, size, false);
2519 
2520 	if (buffer != stackBuffer)
2521 		free(buffer);
2522 
2523 	return error;
2524 }
2525 
2526 
2527 status_t
2528 BMessage::FindString(const char *name, const char **string) const
2529 {
2530 	return FindString(name, 0, string);
2531 }
2532 
2533 
2534 status_t
2535 BMessage::FindString(const char *name, int32 index, const char **string) const
2536 {
2537 	ssize_t bytes;
2538 	return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes);
2539 }
2540 
2541 
2542 status_t
2543 BMessage::FindString(const char *name, BString *string) const
2544 {
2545 	return FindString(name, 0, string);
2546 }
2547 
2548 
2549 status_t
2550 BMessage::FindString(const char *name, int32 index, BString *string) const
2551 {
2552 	if (string == NULL)
2553 		return B_BAD_VALUE;
2554 
2555 	const char *cstr;
2556 	status_t error = FindString(name, index, &cstr);
2557 	if (error < B_OK)
2558 		return error;
2559 
2560 	*string = cstr;
2561 	return B_OK;
2562 }
2563 
2564 
2565 status_t
2566 BMessage::FindPointer(const char *name, void **pointer) const
2567 {
2568 	return FindPointer(name, 0, pointer);
2569 }
2570 
2571 
2572 status_t
2573 BMessage::FindPointer(const char *name, int32 index, void **pointer) const
2574 {
2575 	if (pointer == NULL)
2576 		return B_BAD_VALUE;
2577 
2578 	void **data = NULL;
2579 	ssize_t size = 0;
2580 	status_t error = FindData(name, B_POINTER_TYPE, index,
2581 		(const void **)&data, &size);
2582 
2583 	if (error == B_OK)
2584 		*pointer = *data;
2585 	else
2586 		*pointer = NULL;
2587 
2588 	return error;
2589 }
2590 
2591 
2592 status_t
2593 BMessage::FindMessenger(const char *name, BMessenger *messenger) const
2594 {
2595 	return FindMessenger(name, 0, messenger);
2596 }
2597 
2598 
2599 status_t
2600 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger)
2601 	const
2602 {
2603 	if (messenger == NULL)
2604 		return B_BAD_VALUE;
2605 
2606 	void *data = NULL;
2607 	ssize_t size = 0;
2608 	status_t error = FindData(name, B_MESSENGER_TYPE, index,
2609 		(const void **)&data, &size);
2610 
2611 	if (error == B_OK)
2612 		memcpy(messenger, data, sizeof(BMessenger));
2613 	else
2614 		*messenger = BMessenger();
2615 
2616 	return error;
2617 }
2618 
2619 
2620 status_t
2621 BMessage::FindRef(const char *name, entry_ref *ref) const
2622 {
2623 	return FindRef(name, 0, ref);
2624 }
2625 
2626 
2627 status_t
2628 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const
2629 {
2630 	if (ref == NULL)
2631 		return B_BAD_VALUE;
2632 
2633 	void *data = NULL;
2634 	ssize_t size = 0;
2635 	status_t error = FindData(name, B_REF_TYPE, index,
2636 		(const void **)&data, &size);
2637 
2638 	if (error == B_OK)
2639 		error = BPrivate::entry_ref_unflatten(ref, (char *)data, size);
2640 	else
2641 		*ref = entry_ref();
2642 
2643 	return error;
2644 }
2645 
2646 
2647 status_t
2648 BMessage::FindMessage(const char *name, BMessage *message) const
2649 {
2650 	return FindMessage(name, 0, message);
2651 }
2652 
2653 
2654 status_t
2655 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const
2656 {
2657 	if (message == NULL)
2658 		return B_BAD_VALUE;
2659 
2660 	void *data = NULL;
2661 	ssize_t size = 0;
2662 	status_t error = FindData(name, B_MESSAGE_TYPE, index,
2663 		(const void **)&data, &size);
2664 
2665 	if (error == B_OK)
2666 		error = message->Unflatten((const char *)data);
2667 	else
2668 		*message = BMessage();
2669 
2670 	return error;
2671 }
2672 
2673 
2674 status_t
2675 BMessage::FindFlat(const char *name, BFlattenable *object) const
2676 {
2677 	return FindFlat(name, 0, object);
2678 }
2679 
2680 
2681 status_t
2682 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const
2683 {
2684 	if (object == NULL)
2685 		return B_BAD_VALUE;
2686 
2687 	void *data = NULL;
2688 	ssize_t numBytes = 0;
2689 	status_t error = FindData(name, object->TypeCode(), index,
2690 		(const void **)&data, &numBytes);
2691 
2692 	if (error == B_OK)
2693 		error = object->Unflatten(object->TypeCode(), data, numBytes);
2694 
2695 	return error;
2696 }
2697 
2698 
2699 status_t
2700 BMessage::FindData(const char *name, type_code type, const void **data,
2701 	ssize_t *numBytes) const
2702 {
2703 	return FindData(name, type, 0, data, numBytes);
2704 }
2705 
2706 
2707 status_t
2708 BMessage::ReplaceString(const char *name, const char *string)
2709 {
2710 	if (string == NULL)
2711 		return B_BAD_VALUE;
2712 
2713 	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
2714 }
2715 
2716 
2717 status_t
2718 BMessage::ReplaceString(const char *name, int32 index, const char *string)
2719 {
2720 	if (string == NULL)
2721 		return B_BAD_VALUE;
2722 
2723 	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
2724 }
2725 
2726 
2727 status_t
2728 BMessage::ReplaceString(const char *name, const BString &string)
2729 {
2730 	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
2731 		string.Length() + 1);
2732 }
2733 
2734 
2735 status_t
2736 BMessage::ReplaceString(const char *name, int32 index, const BString &string)
2737 {
2738 	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
2739 		string.Length() + 1);
2740 }
2741 
2742 
2743 status_t
2744 BMessage::ReplacePointer(const char *name, const void *pointer)
2745 {
2746 	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2747 }
2748 
2749 
2750 status_t
2751 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2752 {
2753 	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2754 }
2755 
2756 
2757 status_t
2758 BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2759 {
2760 	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2761 		sizeof(BMessenger));
2762 }
2763 
2764 
2765 status_t
2766 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2767 {
2768 	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2769 		sizeof(BMessenger));
2770 }
2771 
2772 
2773 status_t
2774 BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2775 {
2776 	return ReplaceRef(name, 0, ref);
2777 }
2778 
2779 
2780 status_t
2781 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
2782 {
2783 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2784 	char buffer[size];
2785 
2786 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2787 
2788 	if (error >= B_OK)
2789 		error = ReplaceData(name, B_REF_TYPE, index, &buffer, size);
2790 
2791 	return error;
2792 }
2793 
2794 
2795 status_t
2796 BMessage::ReplaceMessage(const char *name, const BMessage *message)
2797 {
2798 	return ReplaceMessage(name, 0, message);
2799 }
2800 
2801 
2802 status_t
2803 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message)
2804 {
2805 	if (message == NULL)
2806 		return B_BAD_VALUE;
2807 
2808 	ssize_t size = message->FlattenedSize();
2809 	char buffer[size];
2810 
2811 	status_t error = message->Flatten(buffer, size);
2812 
2813 	if (error >= B_OK)
2814 		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
2815 
2816 	return error;
2817 }
2818 
2819 
2820 status_t
2821 BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2822 {
2823 	return ReplaceFlat(name, 0, object);
2824 }
2825 
2826 
2827 status_t
2828 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
2829 {
2830 	if (object == NULL)
2831 		return B_BAD_VALUE;
2832 
2833 	ssize_t size = object->FlattenedSize();
2834 	char buffer[size];
2835 
2836 	status_t error = object->Flatten(buffer, size);
2837 
2838 	if (error >= B_OK)
2839 		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
2840 
2841 	return error;
2842 }
2843 
2844 
2845 status_t
2846 BMessage::ReplaceData(const char *name, type_code type, const void *data,
2847 	ssize_t numBytes)
2848 {
2849 	return ReplaceData(name, type, 0, data, numBytes);
2850 }
2851 
2852 
2853 bool
2854 BMessage::HasFlat(const char *name, const BFlattenable *object) const
2855 {
2856 	return HasFlat(name, 0, object);
2857 }
2858 
2859 
2860 bool
2861 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2862 	const
2863 {
2864 	return HasData(name, object->TypeCode(), index);
2865 }
2866