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