xref: /haiku/src/kits/app/Message.cpp (revision c9ad965c81b08802fed0827fd1dd16f45297928a)
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%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::_StaticReInitForkedChild()
1976 {
1977 	DEBUG_FUNCTION_ENTER2;
1978 
1979 	// overwrite the inherited ports with a set of our own
1980 	sReplyPorts[0] = create_port(1, "tmp_rport0");
1981 	sReplyPorts[1] = create_port(1, "tmp_rport1");
1982 	sReplyPorts[2] = create_port(1, "tmp_rport2");
1983 
1984 	sReplyPortInUse[0] = 0;
1985 	sReplyPortInUse[1] = 0;
1986 	sReplyPortInUse[2] = 0;
1987 }
1988 
1989 
1990 void
1991 BMessage::_StaticCleanup()
1992 {
1993 	DEBUG_FUNCTION_ENTER2;
1994 	delete_port(sReplyPorts[0]);
1995 	sReplyPorts[0] = -1;
1996 	delete_port(sReplyPorts[1]);
1997 	sReplyPorts[1] = -1;
1998 	delete_port(sReplyPorts[2]);
1999 	sReplyPorts[2] = -1;
2000 }
2001 
2002 
2003 void
2004 BMessage::_StaticCacheCleanup()
2005 {
2006 	DEBUG_FUNCTION_ENTER2;
2007 	delete sMsgCache;
2008 	sMsgCache = NULL;
2009 }
2010 
2011 
2012 int32
2013 BMessage::_StaticGetCachedReplyPort()
2014 {
2015 	DEBUG_FUNCTION_ENTER2;
2016 	int index = -1;
2017 	for (int32 i = 0; i < sNumReplyPorts; i++) {
2018 		int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
2019 		if (old == 0) {
2020 			// This entry is free
2021 			index = i;
2022 			break;
2023 		} else {
2024 			// This entry is being used.
2025 			atomic_add(&(sReplyPortInUse[i]), -1);
2026 		}
2027 	}
2028 
2029 	return index;
2030 }
2031 
2032 
2033 status_t
2034 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2035 	bigtime_t timeout, bool replyRequired, BMessenger &replyTo) const
2036 {
2037 	DEBUG_FUNCTION_ENTER;
2038 	ssize_t size = 0;
2039 	char *buffer = NULL;
2040 	message_header *header = NULL;
2041 	status_t result = B_OK;
2042 
2043 	BPrivate::BDirectMessageTarget* direct = NULL;
2044 	BMessage* copy = NULL;
2045 	if (portOwner == BPrivate::current_team())
2046 		BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
2047 
2048 	if (direct != NULL) {
2049 		// We have a direct local message target - we can just enqueue the message
2050 		// in its message queue. This will also prevent possible deadlocks when the
2051 		// queue is full.
2052 		copy = new BMessage(*this);
2053 		if (copy != NULL) {
2054 			header = copy->fHeader;
2055 			header->flags = fHeader->flags;
2056 		} else {
2057 			direct->Release();
2058 			return B_NO_MEMORY;
2059 		}
2060 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2061 	} else if (fHeader->data_size > B_PAGE_SIZE * 10) {
2062 		// ToDo: bind the above size to the max port message size
2063 		// use message passing by area for such a large message
2064 		result = _FlattenToArea(&header);
2065 		if (result != B_OK)
2066 			return result;
2067 
2068 		buffer = (char *)header;
2069 		size = sizeof(message_header);
2070 
2071 		if (header->message_area >= 0) {
2072 			team_id target = portOwner;
2073 			if (target < 0) {
2074 				port_info info;
2075 				result = get_port_info(port, &info);
2076 				if (result != B_OK) {
2077 					free(header);
2078 					return result;
2079 				}
2080 				target = info.team;
2081 			}
2082 
2083 			void *address = NULL;
2084 			area_id transfered = _kern_transfer_area(header->message_area,
2085 				&address, B_ANY_ADDRESS, target);
2086 			if (transfered < 0) {
2087 				delete_area(header->message_area);
2088 				free(header);
2089 				return transfered;
2090 			}
2091 
2092 			header->message_area = transfered;
2093 		}
2094 #endif
2095 	} else {
2096 		size = FlattenedSize();
2097 		buffer = (char *)malloc(size);
2098 		if (buffer == NULL)
2099 			return B_NO_MEMORY;
2100 
2101 		result = Flatten(buffer, size);
2102 		if (result < B_OK) {
2103 			free(buffer);
2104 			return result;
2105 		}
2106 
2107 		header = (message_header *)buffer;
2108 	}
2109 
2110 	if (!replyTo.IsValid()) {
2111 		BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
2112 			fHeader->reply_port, fHeader->reply_target);
2113 
2114 		if (!replyTo.IsValid())
2115 			replyTo = be_app_messenger;
2116 	}
2117 
2118 	BMessenger::Private replyToPrivate(replyTo);
2119 
2120 	if (replyRequired) {
2121 		header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
2122 		header->flags &= ~MESSAGE_FLAG_REPLY_DONE;
2123 	}
2124 
2125 	header->target = token;
2126 	header->reply_team = replyToPrivate.Team();
2127 	header->reply_port = replyToPrivate.Port();
2128 	header->reply_target = replyToPrivate.Token();
2129 	header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2130 
2131 	if (direct == NULL) {
2132 		KTRACE("BMessage send remote: team: %ld, port: %ld, token: %ld, "
2133 			"message: '%c%c%c%c'", portOwner, port, token,
2134 			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2135 
2136 		do {
2137 			result = write_port_etc(port, kPortMessageCode, (void *)buffer,
2138 				size, B_RELATIVE_TIMEOUT, timeout);
2139 		} while (result == B_INTERRUPTED);
2140 	}
2141 
2142 	if (result == B_OK && IsSourceWaiting()) {
2143 		// the forwarded message will handle the reply - we must not do
2144 		// this anymore
2145 		fHeader->flags |= MESSAGE_FLAG_REPLY_DONE;
2146 	}
2147 
2148 	// we need to do this last because it is possible our
2149 	// message might be destroyed after it's enqueued in the
2150 	// target looper. Thus we don't want to do any ops that depend on
2151 	// members of this after the enqueue.
2152 	if (direct != NULL) {
2153 		KTRACE("BMessage send direct: port: %ld, token: %ld, "
2154 			"message: '%c%c%c%c'", port, token,
2155 			char(what >> 24), char(what >> 16), char(what >> 8), (char)what);
2156 
2157 		// this is a local message transmission
2158 		direct->AddMessage(copy);
2159 		if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
2160 			// there is currently no message waiting, and we need to wakeup the looper
2161 			write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
2162 		}
2163 		direct->Release();
2164 	}
2165 
2166 	free(buffer);
2167 	return result;
2168 }
2169 
2170 
2171 /*!
2172 	Sends a message and waits synchronously for a reply.
2173 */
2174 status_t
2175 BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
2176 	BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
2177 {
2178 	if (IsSourceWaiting()) {
2179 		// we can't forward this message synchronously when it's already
2180 		// waiting for a reply
2181 		return B_ERROR;
2182 	}
2183 
2184 	DEBUG_FUNCTION_ENTER;
2185 	const int32 cachedReplyPort = _StaticGetCachedReplyPort();
2186 	port_id replyPort = B_BAD_PORT_ID;
2187 	status_t result = B_OK;
2188 
2189 	if (cachedReplyPort < B_OK) {
2190 		// All the cached reply ports are in use; create a new one
2191 		replyPort = create_port(1 /* for one message */, "tmp_reply_port");
2192 		if (replyPort < B_OK)
2193 			return replyPort;
2194 	} else {
2195 		assert(cachedReplyPort < sNumReplyPorts);
2196 		replyPort = sReplyPorts[cachedReplyPort];
2197 	}
2198 
2199 	team_id team = B_BAD_TEAM_ID;
2200 	if (be_app != NULL)
2201 		team = be_app->Team();
2202 	else {
2203 		port_info portInfo;
2204 		result = get_port_info(replyPort, &portInfo);
2205 		if (result < B_OK)
2206 			goto error;
2207 
2208 		team = portInfo.team;
2209 	}
2210 
2211 	result = set_port_owner(replyPort, portOwner);
2212 	if (result < B_OK)
2213 		goto error;
2214 
2215 	// tests if the queue of the reply port is really empty
2216 #if 0
2217 	port_info portInfo;
2218 	if (get_port_info(replyPort, &portInfo) == B_OK
2219 		&& portInfo.queue_count > 0) {
2220 		debugger("reply port not empty!");
2221 		printf("  reply port not empty! %ld message(s) in queue\n",
2222 			portInfo.queue_count);
2223 
2224 		// fetch and print the messages
2225 		for (int32 i = 0; i < portInfo.queue_count; i++) {
2226 			char buffer[1024];
2227 			int32 code;
2228 			ssize_t size = read_port(replyPort, &code, buffer, sizeof(buffer));
2229 			if (size < 0) {
2230 				printf("failed to read message from reply port\n");
2231 				continue;
2232 			}
2233 			if (size >= (ssize_t)sizeof(buffer)) {
2234 				printf("message from reply port too big\n");
2235 				continue;
2236 			}
2237 
2238 			BMemoryIO stream(buffer, size);
2239 			BMessage reply;
2240 			if (reply.Unflatten(&stream) != B_OK) {
2241 				printf("failed to unflatten message from reply port\n");
2242 				continue;
2243 			}
2244 
2245 			printf("message %ld from reply port:\n", i);
2246 			reply.PrintToStream();
2247 		}
2248 	}
2249 #endif
2250 
2251 	{
2252 		BMessenger replyTarget;
2253 		BMessenger::Private(replyTarget).SetTo(team, replyPort,
2254 			B_PREFERRED_TOKEN);
2255 		// TODO: replying could also use a BDirectMessageTarget like mechanism for local targets
2256 		result = _SendMessage(port, -1, token, sendTimeout, true,
2257 			replyTarget);
2258 	}
2259 
2260 	if (result < B_OK)
2261 		goto error;
2262 
2263 	int32 code;
2264 	result = handle_reply(replyPort, &code, replyTimeout, reply);
2265 	if (result < B_OK && cachedReplyPort >= 0) {
2266 		delete_port(replyPort);
2267 		sReplyPorts[cachedReplyPort] = create_port(1, "tmp_rport");
2268 	}
2269 
2270 error:
2271 	if (cachedReplyPort >= 0) {
2272 		// Reclaim ownership of cached port
2273 		set_port_owner(replyPort, team);
2274 		// Flag as available
2275 		atomic_add(&sReplyPortInUse[cachedReplyPort], -1);
2276 		return result;
2277 	}
2278 
2279 	delete_port(replyPort);
2280 	return result;
2281 }
2282 
2283 
2284 status_t
2285 BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
2286 	int32 token, bigtime_t timeout)
2287 {
2288 	DEBUG_FUNCTION_ENTER2;
2289 	if (data == NULL)
2290 		return B_BAD_VALUE;
2291 
2292 	uint32 magic = *(uint32 *)data;
2293 
2294 	if (magic == MESSAGE_FORMAT_HAIKU || magic == MESSAGE_FORMAT_HAIKU_SWAPPED) {
2295 		message_header *header = (message_header *)data;
2296 		header->target = token;
2297 		header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
2298 	} else if (magic == MESSAGE_FORMAT_R5) {
2299 		uint8 *header = (uint8 *)data;
2300 		header += sizeof(uint32) /* magic */ + sizeof(uint32) /* checksum */
2301 			+ sizeof(ssize_t) /* flattenedSize */ + sizeof(int32) /* what */
2302 			+ sizeof(uint8) /* flags */;
2303 		*(int32 *)header = token;
2304 	} else if (((KMessage::Header *)data)->magic == KMessage::kMessageHeaderMagic) {
2305 		KMessage::Header *header = (KMessage::Header *)data;
2306 		header->targetToken = token;
2307 	} else {
2308 		return B_NOT_A_MESSAGE;
2309 	}
2310 
2311 	// send the message
2312 	status_t result;
2313 
2314 	do {
2315 		result = write_port_etc(port, kPortMessageCode, data, size,
2316 			B_RELATIVE_TIMEOUT, timeout);
2317 	} while (result == B_INTERRUPTED);
2318 
2319 	return result;
2320 }
2321 
2322 
2323 void BMessage::_ReservedMessage1(void) {};
2324 void BMessage::_ReservedMessage2(void) {};
2325 void BMessage::_ReservedMessage3(void) {};
2326 
2327 
2328 /* Relay functions from here on (Add... -> AddData, Find... -> FindData) */
2329 
2330 #define DEFINE_FUNCTIONS(type, typeName, typeCode)							\
2331 status_t																	\
2332 BMessage::Add##typeName(const char *name, type val)							\
2333 {																			\
2334 	return AddData(name, typeCode, &val, sizeof(type), true);				\
2335 }																			\
2336 																			\
2337 status_t																	\
2338 BMessage::Find##typeName(const char *name, 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, 0, (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::Find##typeName(const char *name, int32 index, type *p) const		\
2355 {																			\
2356 	void *ptr = NULL;														\
2357 	ssize_t bytes = 0;														\
2358 	status_t error = B_OK;													\
2359 																			\
2360 	*p = type();															\
2361 	error = FindData(name, typeCode, index, (const void **)&ptr, &bytes);	\
2362 																			\
2363 	if (error == B_OK)														\
2364 		memcpy(p, ptr, sizeof(type));										\
2365 																			\
2366 	return error;															\
2367 }																			\
2368 																			\
2369 status_t																	\
2370 BMessage::Replace##typeName(const char *name, type val)						\
2371 {																			\
2372 	return ReplaceData(name, typeCode, 0, &val, sizeof(type));				\
2373 }																			\
2374 																			\
2375 status_t																	\
2376 BMessage::Replace##typeName(const char *name, int32 index, type val)		\
2377 {																			\
2378 	return ReplaceData(name, typeCode, index, &val, sizeof(type));			\
2379 }																			\
2380 																			\
2381 bool																		\
2382 BMessage::Has##typeName(const char *name, int32 index) const				\
2383 {																			\
2384 	return HasData(name, typeCode, index);									\
2385 }
2386 
2387 DEFINE_FUNCTIONS(BPoint, Point, B_POINT_TYPE);
2388 DEFINE_FUNCTIONS(BRect, Rect, B_RECT_TYPE);
2389 DEFINE_FUNCTIONS(int8, Int8, B_INT8_TYPE);
2390 DEFINE_FUNCTIONS(uint8, UInt8, B_UINT8_TYPE);
2391 DEFINE_FUNCTIONS(int16, Int16, B_INT16_TYPE);
2392 DEFINE_FUNCTIONS(uint16, UInt16, B_UINT16_TYPE);
2393 DEFINE_FUNCTIONS(int32, Int32, B_INT32_TYPE);
2394 DEFINE_FUNCTIONS(uint32, UInt32, B_UINT32_TYPE);
2395 DEFINE_FUNCTIONS(int64, Int64, B_INT64_TYPE);
2396 DEFINE_FUNCTIONS(uint64, UInt64, B_UINT64_TYPE);
2397 DEFINE_FUNCTIONS(bool, Bool, B_BOOL_TYPE);
2398 DEFINE_FUNCTIONS(float, Float, B_FLOAT_TYPE);
2399 DEFINE_FUNCTIONS(double, Double, B_DOUBLE_TYPE);
2400 
2401 #undef DEFINE_FUNCTIONS
2402 
2403 #define DEFINE_HAS_FUNCTION(typeName, typeCode)								\
2404 bool																		\
2405 BMessage::Has##typeName(const char *name, int32 index) const				\
2406 {																			\
2407 	return HasData(name, typeCode, index);									\
2408 }
2409 
2410 DEFINE_HAS_FUNCTION(String, B_STRING_TYPE);
2411 DEFINE_HAS_FUNCTION(Pointer, B_POINTER_TYPE);
2412 DEFINE_HAS_FUNCTION(Messenger, B_MESSENGER_TYPE);
2413 DEFINE_HAS_FUNCTION(Ref, B_REF_TYPE);
2414 DEFINE_HAS_FUNCTION(Message, B_MESSAGE_TYPE);
2415 
2416 #undef DEFINE_HAS_FUNCTION
2417 
2418 #define DEFINE_LAZY_FIND_FUNCTION(type, typeName, initialize)				\
2419 type																		\
2420 BMessage::Find##typeName(const char *name, int32 index) const				\
2421 {																			\
2422 	type val = initialize;													\
2423 	Find##typeName(name, index, &val);										\
2424 	return val;																\
2425 }
2426 
2427 DEFINE_LAZY_FIND_FUNCTION(BRect, Rect, BRect());
2428 DEFINE_LAZY_FIND_FUNCTION(BPoint, Point, BPoint());
2429 DEFINE_LAZY_FIND_FUNCTION(const char *, String, NULL);
2430 DEFINE_LAZY_FIND_FUNCTION(int8, Int8, 0);
2431 DEFINE_LAZY_FIND_FUNCTION(int16, Int16, 0);
2432 DEFINE_LAZY_FIND_FUNCTION(int32, Int32, 0);
2433 DEFINE_LAZY_FIND_FUNCTION(int64, Int64, 0);
2434 DEFINE_LAZY_FIND_FUNCTION(bool, Bool, false);
2435 DEFINE_LAZY_FIND_FUNCTION(float, Float, 0);
2436 DEFINE_LAZY_FIND_FUNCTION(double, Double, 0);
2437 
2438 #undef DEFINE_LAZY_FIND_FUNCTION
2439 
2440 status_t
2441 BMessage::AddString(const char *name, const char *string)
2442 {
2443 	return AddData(name, B_STRING_TYPE, string, string ? strlen(string) + 1 : 0, false);
2444 }
2445 
2446 
2447 status_t
2448 BMessage::AddString(const char *name, const BString &string)
2449 {
2450 	return AddData(name, B_STRING_TYPE, string.String(), string.Length() + 1, false);
2451 }
2452 
2453 
2454 status_t
2455 BMessage::AddPointer(const char *name, const void *pointer)
2456 {
2457 	return AddData(name, B_POINTER_TYPE, &pointer, sizeof(pointer), true);
2458 }
2459 
2460 
2461 status_t
2462 BMessage::AddMessenger(const char *name, BMessenger messenger)
2463 {
2464 	return AddData(name, B_MESSENGER_TYPE, &messenger, sizeof(messenger), true);
2465 }
2466 
2467 
2468 status_t
2469 BMessage::AddRef(const char *name, const entry_ref *ref)
2470 {
2471 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2472 	char buffer[size];
2473 
2474 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2475 
2476 	if (error >= B_OK)
2477 		error = AddData(name, B_REF_TYPE, buffer, size, false);
2478 
2479 	return error;
2480 }
2481 
2482 
2483 status_t
2484 BMessage::AddMessage(const char *name, const BMessage *message)
2485 {
2486 	if (message == NULL)
2487 		return B_BAD_VALUE;
2488 
2489 	// TODO: This and the following functions waste time by allocating and
2490 	// copying an extra buffer. Functions can be added that return a direct
2491 	// pointer into the message.
2492 
2493 	char stackBuffer[16384];
2494 	ssize_t size = message->FlattenedSize();
2495 
2496 	char* buffer;
2497 	if (size > (ssize_t)sizeof(stackBuffer)) {
2498 		buffer = (char *)malloc(size);
2499 		if (buffer == NULL)
2500 			return B_NO_MEMORY;
2501 	} else
2502 		buffer = stackBuffer;
2503 
2504 	status_t error = message->Flatten(buffer, size);
2505 
2506 	if (error >= B_OK)
2507 		error = AddData(name, B_MESSAGE_TYPE, buffer, size, false);
2508 
2509 	if (buffer != stackBuffer)
2510 		free(buffer);
2511 
2512 	return error;
2513 }
2514 
2515 
2516 status_t
2517 BMessage::AddFlat(const char *name, BFlattenable *object, int32 count)
2518 {
2519 	if (object == NULL)
2520 		return B_BAD_VALUE;
2521 
2522 	char stackBuffer[16384];
2523 	ssize_t size = object->FlattenedSize();
2524 
2525 	char* buffer;
2526 	if (size > (ssize_t)sizeof(stackBuffer)) {
2527 		buffer = (char *)malloc(size);
2528 		if (buffer == NULL)
2529 			return B_NO_MEMORY;
2530 	} else
2531 		buffer = stackBuffer;
2532 
2533 	status_t error = object->Flatten(buffer, size);
2534 
2535 	if (error >= B_OK)
2536 		error = AddData(name, object->TypeCode(), buffer, size, false);
2537 
2538 	if (buffer != stackBuffer)
2539 		free(buffer);
2540 
2541 	return error;
2542 }
2543 
2544 
2545 status_t
2546 BMessage::FindString(const char *name, const char **string) const
2547 {
2548 	return FindString(name, 0, string);
2549 }
2550 
2551 
2552 status_t
2553 BMessage::FindString(const char *name, int32 index, const char **string) const
2554 {
2555 	ssize_t bytes;
2556 	return FindData(name, B_STRING_TYPE, index, (const void **)string, &bytes);
2557 }
2558 
2559 
2560 status_t
2561 BMessage::FindString(const char *name, BString *string) const
2562 {
2563 	return FindString(name, 0, string);
2564 }
2565 
2566 
2567 status_t
2568 BMessage::FindString(const char *name, int32 index, BString *string) const
2569 {
2570 	if (string == NULL)
2571 		return B_BAD_VALUE;
2572 
2573 	const char *cstr;
2574 	status_t error = FindString(name, index, &cstr);
2575 	if (error < B_OK)
2576 		return error;
2577 
2578 	*string = cstr;
2579 	return B_OK;
2580 }
2581 
2582 
2583 status_t
2584 BMessage::FindPointer(const char *name, void **pointer) const
2585 {
2586 	return FindPointer(name, 0, pointer);
2587 }
2588 
2589 
2590 status_t
2591 BMessage::FindPointer(const char *name, int32 index, void **pointer) const
2592 {
2593 	if (pointer == NULL)
2594 		return B_BAD_VALUE;
2595 
2596 	void **data = NULL;
2597 	ssize_t size = 0;
2598 	status_t error = FindData(name, B_POINTER_TYPE, index,
2599 		(const void **)&data, &size);
2600 
2601 	if (error == B_OK)
2602 		*pointer = *data;
2603 	else
2604 		*pointer = NULL;
2605 
2606 	return error;
2607 }
2608 
2609 
2610 status_t
2611 BMessage::FindMessenger(const char *name, BMessenger *messenger) const
2612 {
2613 	return FindMessenger(name, 0, messenger);
2614 }
2615 
2616 
2617 status_t
2618 BMessage::FindMessenger(const char *name, int32 index, BMessenger *messenger)
2619 	const
2620 {
2621 	if (messenger == NULL)
2622 		return B_BAD_VALUE;
2623 
2624 	void *data = NULL;
2625 	ssize_t size = 0;
2626 	status_t error = FindData(name, B_MESSENGER_TYPE, index,
2627 		(const void **)&data, &size);
2628 
2629 	if (error == B_OK)
2630 		memcpy(messenger, data, sizeof(BMessenger));
2631 	else
2632 		*messenger = BMessenger();
2633 
2634 	return error;
2635 }
2636 
2637 
2638 status_t
2639 BMessage::FindRef(const char *name, entry_ref *ref) const
2640 {
2641 	return FindRef(name, 0, ref);
2642 }
2643 
2644 
2645 status_t
2646 BMessage::FindRef(const char *name, int32 index, entry_ref *ref) const
2647 {
2648 	if (ref == NULL)
2649 		return B_BAD_VALUE;
2650 
2651 	void *data = NULL;
2652 	ssize_t size = 0;
2653 	status_t error = FindData(name, B_REF_TYPE, index,
2654 		(const void **)&data, &size);
2655 
2656 	if (error == B_OK)
2657 		error = BPrivate::entry_ref_unflatten(ref, (char *)data, size);
2658 	else
2659 		*ref = entry_ref();
2660 
2661 	return error;
2662 }
2663 
2664 
2665 status_t
2666 BMessage::FindMessage(const char *name, BMessage *message) const
2667 {
2668 	return FindMessage(name, 0, message);
2669 }
2670 
2671 
2672 status_t
2673 BMessage::FindMessage(const char *name, int32 index, BMessage *message) const
2674 {
2675 	if (message == NULL)
2676 		return B_BAD_VALUE;
2677 
2678 	void *data = NULL;
2679 	ssize_t size = 0;
2680 	status_t error = FindData(name, B_MESSAGE_TYPE, index,
2681 		(const void **)&data, &size);
2682 
2683 	if (error == B_OK)
2684 		error = message->Unflatten((const char *)data);
2685 	else
2686 		*message = BMessage();
2687 
2688 	return error;
2689 }
2690 
2691 
2692 status_t
2693 BMessage::FindFlat(const char *name, BFlattenable *object) const
2694 {
2695 	return FindFlat(name, 0, object);
2696 }
2697 
2698 
2699 status_t
2700 BMessage::FindFlat(const char *name, int32 index, BFlattenable *object) const
2701 {
2702 	if (object == NULL)
2703 		return B_BAD_VALUE;
2704 
2705 	void *data = NULL;
2706 	ssize_t numBytes = 0;
2707 	status_t error = FindData(name, object->TypeCode(), index,
2708 		(const void **)&data, &numBytes);
2709 
2710 	if (error == B_OK)
2711 		error = object->Unflatten(object->TypeCode(), data, numBytes);
2712 
2713 	return error;
2714 }
2715 
2716 
2717 status_t
2718 BMessage::FindData(const char *name, type_code type, const void **data,
2719 	ssize_t *numBytes) const
2720 {
2721 	return FindData(name, type, 0, data, numBytes);
2722 }
2723 
2724 
2725 status_t
2726 BMessage::ReplaceString(const char *name, const char *string)
2727 {
2728 	if (string == NULL)
2729 		return B_BAD_VALUE;
2730 
2731 	return ReplaceData(name, B_STRING_TYPE, 0, string, strlen(string) + 1);
2732 }
2733 
2734 
2735 status_t
2736 BMessage::ReplaceString(const char *name, int32 index, const char *string)
2737 {
2738 	if (string == NULL)
2739 		return B_BAD_VALUE;
2740 
2741 	return ReplaceData(name, B_STRING_TYPE, index, string, strlen(string) + 1);
2742 }
2743 
2744 
2745 status_t
2746 BMessage::ReplaceString(const char *name, const BString &string)
2747 {
2748 	return ReplaceData(name, B_STRING_TYPE, 0, string.String(),
2749 		string.Length() + 1);
2750 }
2751 
2752 
2753 status_t
2754 BMessage::ReplaceString(const char *name, int32 index, const BString &string)
2755 {
2756 	return ReplaceData(name, B_STRING_TYPE, index, string.String(),
2757 		string.Length() + 1);
2758 }
2759 
2760 
2761 status_t
2762 BMessage::ReplacePointer(const char *name, const void *pointer)
2763 {
2764 	return ReplaceData(name, B_POINTER_TYPE, 0, &pointer, sizeof(pointer));
2765 }
2766 
2767 
2768 status_t
2769 BMessage::ReplacePointer(const char *name, int32 index, const void *pointer)
2770 {
2771 	return ReplaceData(name, B_POINTER_TYPE, index, &pointer, sizeof(pointer));
2772 }
2773 
2774 
2775 status_t
2776 BMessage::ReplaceMessenger(const char *name, BMessenger messenger)
2777 {
2778 	return ReplaceData(name, B_MESSENGER_TYPE, 0, &messenger,
2779 		sizeof(BMessenger));
2780 }
2781 
2782 
2783 status_t
2784 BMessage::ReplaceMessenger(const char *name, int32 index, BMessenger messenger)
2785 {
2786 	return ReplaceData(name, B_MESSENGER_TYPE, index, &messenger,
2787 		sizeof(BMessenger));
2788 }
2789 
2790 
2791 status_t
2792 BMessage::ReplaceRef(const char *name, const entry_ref *ref)
2793 {
2794 	return ReplaceRef(name, 0, ref);
2795 }
2796 
2797 
2798 status_t
2799 BMessage::ReplaceRef(const char *name, int32 index, const entry_ref *ref)
2800 {
2801 	size_t size = sizeof(entry_ref) + B_PATH_NAME_LENGTH;
2802 	char buffer[size];
2803 
2804 	status_t error = BPrivate::entry_ref_flatten(buffer, &size, ref);
2805 
2806 	if (error >= B_OK)
2807 		error = ReplaceData(name, B_REF_TYPE, index, &buffer, size);
2808 
2809 	return error;
2810 }
2811 
2812 
2813 status_t
2814 BMessage::ReplaceMessage(const char *name, const BMessage *message)
2815 {
2816 	return ReplaceMessage(name, 0, message);
2817 }
2818 
2819 
2820 status_t
2821 BMessage::ReplaceMessage(const char *name, int32 index, const BMessage *message)
2822 {
2823 	if (message == NULL)
2824 		return B_BAD_VALUE;
2825 
2826 	ssize_t size = message->FlattenedSize();
2827 	char buffer[size];
2828 
2829 	status_t error = message->Flatten(buffer, size);
2830 
2831 	if (error >= B_OK)
2832 		error = ReplaceData(name, B_MESSAGE_TYPE, index, &buffer, size);
2833 
2834 	return error;
2835 }
2836 
2837 
2838 status_t
2839 BMessage::ReplaceFlat(const char *name, BFlattenable *object)
2840 {
2841 	return ReplaceFlat(name, 0, object);
2842 }
2843 
2844 
2845 status_t
2846 BMessage::ReplaceFlat(const char *name, int32 index, BFlattenable *object)
2847 {
2848 	if (object == NULL)
2849 		return B_BAD_VALUE;
2850 
2851 	ssize_t size = object->FlattenedSize();
2852 	char buffer[size];
2853 
2854 	status_t error = object->Flatten(buffer, size);
2855 
2856 	if (error >= B_OK)
2857 		error = ReplaceData(name, object->TypeCode(), index, &buffer, size);
2858 
2859 	return error;
2860 }
2861 
2862 
2863 status_t
2864 BMessage::ReplaceData(const char *name, type_code type, const void *data,
2865 	ssize_t numBytes)
2866 {
2867 	return ReplaceData(name, type, 0, data, numBytes);
2868 }
2869 
2870 
2871 bool
2872 BMessage::HasFlat(const char *name, const BFlattenable *object) const
2873 {
2874 	return HasFlat(name, 0, object);
2875 }
2876 
2877 
2878 bool
2879 BMessage::HasFlat(const char *name, int32 index, const BFlattenable *object)
2880 	const
2881 {
2882 	return HasData(name, object->TypeCode(), index);
2883 }
2884