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