xref: /haiku/src/system/kernel/messaging/KMessage.cpp (revision d0aa07489c022f98519a79cbd5ceea5ac060d4d6)
1 /*
2  * Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <util/KMessage.h>
8 
9 #include <malloc.h>
10 	// for memalign()
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <ByteOrder.h>
15 #include <Debug.h>
16 #include <KernelExport.h>
17 #include <TypeConstants.h>
18 
19 
20 #if defined(_BOOT_MODE) || defined(_LOADER_MODE)
21 #	include <util/kernel_cpp.h>
22 #else
23 #	include <new>
24 #endif
25 
26 
27 // TODO: Add a field index using a hash map, so that lookup improves to O(1)
28 // (is now O(n)).
29 
30 
31 // define the PANIC macro
32 #ifndef PANIC
33 #	ifdef _KERNEL_MODE
34 #		define PANIC(str)	panic(str)
35 #	else
36 #		define PANIC(str)	debugger(str)
37 #	endif
38 #endif
39 
40 
41 static const int32 kMessageReallocChunkSize = 64;
42 static const size_t kMessageBufferAlignment = 4;
43 
44 const uint32 KMessage::kMessageHeaderMagic = 'kMsG';
45 
46 
47 // #pragma mark - Helper Functions
48 
49 static inline int32
50 _Align(int32 offset)
51 {
52 	return (offset + kMessageBufferAlignment - 1)
53 		& ~(kMessageBufferAlignment - 1);
54 }
55 
56 
57 static inline void*
58 _Align(void* address, int32 offset = 0)
59 {
60 	return (void*)(((addr_t)address + offset + kMessageBufferAlignment - 1)
61 		& ~(kMessageBufferAlignment - 1));
62 }
63 
64 
65 // #pragma mark - FieldValueHeader
66 
67 
68 struct KMessage::FieldValueHeader {
69 	int32		size;
70 
71 	void* Data()
72 	{
73 		return _Align(this, sizeof(FieldValueHeader));
74 	}
75 
76 	FieldValueHeader* NextFieldValueHeader()
77 	{
78 		return (FieldValueHeader*)_Align(Data(), size);
79 	}
80 };
81 
82 
83 // #pragma mark - FieldHeader
84 
85 
86 struct KMessage::FieldHeader {
87 	type_code	type;
88 	int32		elementSize;	// if < 0: non-fixed size
89 	int32		elementCount;
90 	int32		fieldSize;
91 	int16		headerSize;
92 	char		name[1];
93 
94 	void* Data()
95 	{
96 		return (uint8*)this + headerSize;
97 	}
98 
99 	bool HasFixedElementSize()
100 	{
101 		return elementSize >= 0;
102 	}
103 
104 	void* ElementAt(int32 index, int32* size)
105 	{
106 		if (index < 0 || index >= elementCount)
107 			return NULL;
108 		uint8* data = (uint8*)this + headerSize;
109 		if (HasFixedElementSize()) {
110 			*size = elementSize;
111 			return data + elementSize * index;
112 		}
113 		// non-fixed element size: we need to iterate
114 		FieldValueHeader* valueHeader = (FieldValueHeader*)data;
115 		for (int i = 0; i < index; i++)
116 			valueHeader = valueHeader->NextFieldValueHeader();
117 		*size = valueHeader->size;
118 		return valueHeader->Data();
119 	}
120 
121 	FieldHeader* NextFieldHeader()
122 	{
123 		return (FieldHeader*)_Align(this, fieldSize);
124 	}
125 };
126 
127 
128 // #pragma mark - KMessage
129 
130 
131 KMessage::KMessage()
132 	:
133 	fBuffer(NULL),
134 	fBufferCapacity(0),
135 	fFlags(0),
136 	fLastFieldOffset(0)
137 {
138 	Unset();
139 }
140 
141 
142 KMessage::KMessage(uint32 what)
143 	:
144 	fBuffer(NULL),
145 	fBufferCapacity(0),
146 	fFlags(0),
147 	fLastFieldOffset(0)
148 {
149 	Unset();
150 	SetWhat(what);
151 }
152 
153 
154 KMessage::~KMessage()
155 {
156 	Unset();
157 }
158 
159 
160 status_t
161 KMessage::SetTo(uint32 what, uint32 flags)
162 {
163 	// There are no flags interesting in this case at the moment.
164 	Unset();
165 	SetWhat(what);
166 	return B_OK;
167 }
168 
169 
170 status_t
171 KMessage::SetTo(void* buffer, int32 bufferSize, uint32 what, uint32 flags)
172 {
173 	Unset();
174 
175 	if (!buffer)
176 		return B_BAD_VALUE;
177 
178 	if (bufferSize < 0) {
179 		if (!(flags & KMESSAGE_INIT_FROM_BUFFER))
180 			return B_BAD_VALUE;
181 	} else if (bufferSize < (int)sizeof(Header))
182 		return B_BAD_VALUE;
183 
184 	// if read-only, we need to init from the buffer, too
185 	if ((flags & KMESSAGE_READ_ONLY) != 0
186 		&& (flags & KMESSAGE_INIT_FROM_BUFFER) == 0) {
187 		return B_BAD_VALUE;
188 	}
189 
190 	// if not initializing from the given buffer, cloning it doesn't make sense
191 	if ((flags & KMESSAGE_INIT_FROM_BUFFER) == 0
192 		&& (flags & KMESSAGE_CLONE_BUFFER) != 0) {
193 		return B_BAD_VALUE;
194 	}
195 
196 	fBuffer = buffer;
197 	fBufferCapacity = bufferSize;
198 	fFlags = flags;
199 
200 	status_t error = B_OK;
201 	if (flags & KMESSAGE_INIT_FROM_BUFFER)
202 		error = _InitFromBuffer(bufferSize < 0);
203 	else
204 		_InitBuffer(what);
205 
206 	if (error != B_OK)
207 		Unset();
208 
209 	return error;
210 }
211 
212 
213 status_t
214 KMessage::SetTo(const void* buffer, int32 bufferSize, uint32 flags)
215 {
216 	return SetTo(const_cast<void*>(buffer), bufferSize, 0,
217 		KMESSAGE_INIT_FROM_BUFFER | KMESSAGE_READ_ONLY | flags);
218 }
219 
220 
221 void
222 KMessage::Unset()
223 {
224 	// free buffer
225 	if (fBuffer && fBuffer != &fHeader && (fFlags & KMESSAGE_OWNS_BUFFER))
226 		free(fBuffer);
227 	fBuffer = &fHeader;
228 	fBufferCapacity = sizeof(Header);
229 	_InitBuffer(0);
230 }
231 
232 
233 void
234 KMessage::SetWhat(uint32 what)
235 {
236 	_Header()->what = what;
237 }
238 
239 
240 uint32
241 KMessage::What() const
242 {
243 	return _Header()->what;
244 }
245 
246 
247 const void*
248 KMessage::Buffer() const
249 {
250 	return fBuffer;
251 }
252 
253 
254 int32
255 KMessage::BufferCapacity() const
256 {
257 	return fBufferCapacity;
258 }
259 
260 
261 int32
262 KMessage::ContentSize() const
263 {
264 	return _Header()->size;
265 }
266 
267 
268 status_t
269 KMessage::AddField(const char* name, type_code type, int32 elementSize,
270 	KMessageField* field)
271 {
272 	if (!name || type == B_ANY_TYPE)
273 		return B_BAD_VALUE;
274 	KMessageField existingField;
275 	if (FindField(name, &existingField) == B_OK)
276 		return B_NAME_IN_USE;
277 	return _AddField(name, type, elementSize, field);
278 }
279 
280 
281 status_t
282 KMessage::FindField(const char* name, KMessageField* field) const
283 {
284 	return FindField(name, B_ANY_TYPE, field);
285 }
286 
287 
288 status_t
289 KMessage::FindField(const char* name, type_code type,
290 	KMessageField* field) const
291 {
292 	if (!name)
293 		return B_BAD_VALUE;
294 	KMessageField stackField;
295 	if (field)
296 		field->Unset();
297 	else
298 		field = &stackField;
299 	while (GetNextField(field) == B_OK) {
300 		if ((type == B_ANY_TYPE || field->TypeCode() == type)
301 			&& strcmp(name, field->Name()) == 0) {
302 			return B_OK;
303 		}
304 	}
305 	return B_NAME_NOT_FOUND;
306 }
307 
308 
309 status_t
310 KMessage::GetNextField(KMessageField* field) const
311 {
312 	if (!field || (field->Message() != NULL && field->Message() != this))
313 		return B_BAD_VALUE;
314 	FieldHeader* fieldHeader = field->_Header();
315 	FieldHeader* lastField = _LastFieldHeader();
316 	if (!lastField)
317 		return B_NAME_NOT_FOUND;
318 	if (fieldHeader == NULL) {
319 		fieldHeader = _FirstFieldHeader();
320 	} else {
321 		if ((uint8*)fieldHeader < (uint8*)_FirstFieldHeader()
322 			|| (uint8*)fieldHeader > (uint8*)lastField) {
323 			return B_BAD_VALUE;
324 		}
325 		if (fieldHeader == lastField)
326 			return B_NAME_NOT_FOUND;
327 		fieldHeader = fieldHeader->NextFieldHeader();
328 	}
329 	field->SetTo(const_cast<KMessage*>(this), _BufferOffsetFor(fieldHeader));
330 	return B_OK;
331 }
332 
333 
334 bool
335 KMessage::IsEmpty() const
336 {
337 	return _LastFieldHeader() == NULL;
338 }
339 
340 
341 status_t
342 KMessage::AddData(const char* name, type_code type, const void* data,
343 	int32 numBytes, bool isFixedSize)
344 {
345 	if (!name || type == B_ANY_TYPE || !data || numBytes < 0)
346 		return B_BAD_VALUE;
347 	KMessageField field;
348 	if (FindField(name, &field) == B_OK) {
349 		// field with that name already exists: check its type
350 		if (field.TypeCode() != type)
351 			return B_BAD_TYPE;
352 	} else {
353 		// no such field yet: add it
354 		status_t error = _AddField(name, type, (isFixedSize ? numBytes : -1),
355 			&field);
356 		if (error != B_OK)
357 			return error;
358 	}
359 	return _AddFieldData(&field, data, numBytes, 1);
360 }
361 
362 
363 status_t
364 KMessage::AddArray(const char* name, type_code type, const void* data,
365 	int32 elementSize, int32 elementCount)
366 {
367 	if (!name || type == B_ANY_TYPE || !data || elementSize < 0
368 		|| elementCount < 0) {
369 		return B_BAD_VALUE;
370 	}
371 	KMessageField field;
372 	if (FindField(name, &field) == B_OK) {
373 		// field with that name already exists: check its type
374 		if (field.TypeCode() != type)
375 			return B_BAD_TYPE;
376 	} else {
377 		// no such field yet: add it
378 		status_t error = _AddField(name, type, elementSize, &field);
379 		if (error != B_OK)
380 			return error;
381 	}
382 	return _AddFieldData(&field, data, elementSize, elementCount);
383 }
384 
385 
386 status_t
387 KMessage::SetData(const char* name, type_code type, const void* data,
388 	int32 numBytes)
389 {
390 	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
391 		return B_NOT_ALLOWED;
392 
393 	KMessageField field;
394 
395 	if (FindField(name, &field) == B_OK) {
396 		// field already known
397 		if (field.TypeCode() != type || !field.HasFixedElementSize()
398 			|| field.ElementSize() != numBytes) {
399 			return B_BAD_VALUE;
400 		}
401 
402 		// if it has an element, just replace its value
403 		if (field.CountElements() > 0) {
404 			const void* element = field.ElementAt(0);
405 			memcpy(const_cast<void*>(element), data, numBytes);
406 			return B_OK;
407 		}
408 	} else {
409 		// no such field yet -- add it
410 		status_t error = _AddField(name, type, numBytes, &field);
411 		if (error != B_OK)
412 			return error;
413 	}
414 
415 	// we've got an empty field -- add the element
416 	return _AddFieldData(&field, data, numBytes, 1);
417 }
418 
419 
420 status_t
421 KMessage::FindData(const char* name, type_code type, const void** data,
422 	int32* numBytes) const
423 {
424 	return FindData(name, type, 0, data, numBytes);
425 }
426 
427 
428 status_t
429 KMessage::FindData(const char* name, type_code type, int32 index,
430 	const void** data, int32* numBytes) const
431 {
432 	if (!name || !data || !numBytes)
433 		return B_BAD_VALUE;
434 	KMessageField field;
435 	status_t error = FindField(name, type, &field);
436 	if (error != B_OK)
437 		return error;
438 	const void* foundData = field.ElementAt(index, numBytes);
439 	if (!foundData)
440 		return B_BAD_INDEX;
441 	if (data)
442 		*data = foundData;
443 	return B_OK;
444 }
445 
446 
447 team_id
448 KMessage::Sender() const
449 {
450 	return _Header()->sender;
451 }
452 
453 
454 int32
455 KMessage::TargetToken() const
456 {
457 	return _Header()->targetToken;
458 }
459 
460 
461 port_id
462 KMessage::ReplyPort() const
463 {
464 	return _Header()->replyPort;
465 }
466 
467 
468 int32
469 KMessage::ReplyToken() const
470 {
471 	return _Header()->replyToken;
472 }
473 
474 
475 void
476 KMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort,
477 	int32 replyToken, team_id senderTeam)
478 {
479 	Header* header = _Header();
480 	header->sender = senderTeam;
481 	header->targetToken = targetToken;
482 	header->replyPort = replyPort;
483 	header->replyToken = replyToken;
484 	header->sender = senderTeam;
485 }
486 
487 
488 #ifndef KMESSAGE_CONTAINER_ONLY
489 
490 
491 status_t
492 KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort,
493 	int32 replyToken, bigtime_t timeout, team_id senderTeam)
494 {
495 	// get the sender team
496 	if (senderTeam < 0) {
497 		thread_info info;
498 		status_t error = get_thread_info(find_thread(NULL), &info);
499 		if (error != B_OK)
500 			return error;
501 
502 		senderTeam = info.team;
503 	}
504 
505 	SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam);
506 
507 	// send the message
508 	if (timeout < 0)
509 		return write_port(targetPort, 'KMSG', fBuffer, ContentSize());
510 
511 	return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(),
512 		B_RELATIVE_TIMEOUT, timeout);
513 }
514 
515 
516 status_t
517 KMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply,
518 	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
519 {
520 	// get the team the target port belongs to
521 	port_info portInfo;
522 	status_t error = get_port_info(targetPort, &portInfo);
523 	if (error != B_OK)
524 		return error;
525 	team_id targetTeam = portInfo.team;
526 	// allocate a reply port, if a reply is desired
527 	port_id replyPort = -1;
528 	if (reply) {
529 		// get our team
530 		team_id ourTeam = B_SYSTEM_TEAM;
531 		#ifndef _KERNEL_MODE
532 			if (targetTeam != B_SYSTEM_TEAM) {
533 				thread_info threadInfo;
534 				error = get_thread_info(find_thread(NULL), &threadInfo);
535 				if (error != B_OK)
536 					return error;
537 				ourTeam = threadInfo.team;
538 			}
539 		#endif
540 		// create the port
541 		replyPort = create_port(1, "KMessage reply port");
542 		if (replyPort < 0)
543 			return replyPort;
544 		// If the target team is not our team and not the kernel team either,
545 		// we transfer the ownership of the port to it, so we will not block
546 		if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM)
547 			set_port_owner(replyPort, targetTeam);
548 	}
549 	struct PortDeleter {
550 		PortDeleter(port_id port) : port(port) {}
551 		~PortDeleter()
552 		{
553 			if (port >= 0)
554 				delete_port(port);
555 		}
556 
557 		port_id	port;
558 	} replyPortDeleter(replyPort);
559 	// send the message
560 	error = SendTo(targetPort, targetToken, replyPort, 0,
561 		deliveryTimeout, senderTeam);
562 	if (error != B_OK)
563 		return error;
564 	// get the reply
565 	if (reply)
566 		return reply->ReceiveFrom(replyPort, replyTimeout);
567 	return B_OK;
568 }
569 
570 
571 status_t
572 KMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken,
573 	bigtime_t timeout, team_id senderTeam)
574 {
575 	if (!message)
576 		return B_BAD_VALUE;
577 	return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken,
578 		timeout, senderTeam);
579 }
580 
581 
582 status_t
583 KMessage::SendReply(KMessage* message, KMessage* reply,
584 	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
585 {
586 	if (!message)
587 		return B_BAD_VALUE;
588 	return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout,
589 		replyTimeout, senderTeam);
590 }
591 
592 
593 status_t
594 KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout,
595 	port_message_info* messageInfo)
596 {
597 	port_message_info _messageInfo;
598 	if (messageInfo == NULL)
599 		messageInfo = &_messageInfo;
600 
601 	// get the port buffer size
602 	status_t error;
603 	if (timeout < 0) {
604 		error = get_port_message_info_etc(fromPort, messageInfo, 0, 0);
605 	} else {
606 		error = get_port_message_info_etc(fromPort, messageInfo,
607 			B_RELATIVE_TIMEOUT, timeout);
608 	}
609 	if (error != B_OK)
610 		return error;
611 
612 	// allocate a buffer
613 	uint8* buffer = (uint8*)memalign(kMessageBufferAlignment,
614 		messageInfo->size);
615 	if (!buffer)
616 		return B_NO_MEMORY;
617 
618 	// read the message
619 	int32 what;
620 	ssize_t realSize = read_port_etc(fromPort, &what, buffer, messageInfo->size,
621 		B_RELATIVE_TIMEOUT, 0);
622 	if (realSize < 0) {
623 		free(buffer);
624 		return realSize;
625 	}
626 	if (messageInfo->size != (size_t)realSize) {
627 		free(buffer);
628 		return B_ERROR;
629 	}
630 
631 	// init the message
632 	return SetTo(buffer, messageInfo->size, 0,
633 		KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER);
634 }
635 
636 
637 #endif	// !KMESSAGE_CONTAINER_ONLY
638 
639 
640 void
641 KMessage::Dump(void (*printFunc)(const char*, ...)) const
642 {
643 	Header* header = _Header();
644 	printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: %#"
645 		B_PRIx32 "\n", fBuffer, header->size, fBufferCapacity, fFlags);
646 
647 	KMessageField field;
648 	while (GetNextField(&field) == B_OK) {
649 		type_code type = field.TypeCode();
650 		uint32 bigEndianType = B_HOST_TO_BENDIAN_INT32(type);
651 		int nameSpacing = 17 - strlen(field.Name());
652 		if (nameSpacing < 0)
653 			nameSpacing = 0;
654 
655 		printFunc("  field: \"%s\"%*s (%.4s): ", field.Name(), nameSpacing, "",
656 			(char*)&bigEndianType);
657 
658 		if (field.CountElements() != 1)
659 			printFunc("\n");
660 
661 		int32 size;
662 		for (int i = 0; const void* data = field.ElementAt(i, &size); i++) {
663 			if (field.CountElements() != 1)
664 				printFunc("    [%2d] ", i);
665 
666 			bool isIntType = false;
667 			int64 intData = 0;
668 			switch (type) {
669 				case B_BOOL_TYPE:
670 					printFunc("%s\n", (*(bool*)data ? "true" : "false"));
671 					break;
672 				case B_INT8_TYPE:
673 					isIntType = true;
674 					intData = *(int8*)data;
675 					break;
676 				case B_INT16_TYPE:
677 					isIntType = true;
678 					intData = *(int16*)data;
679 					break;
680 				case B_INT32_TYPE:
681 					isIntType = true;
682 					intData = *(int32*)data;
683 					break;
684 				case B_INT64_TYPE:
685 					isIntType = true;
686 					intData = *(int64*)data;
687 					break;
688 				case B_STRING_TYPE:
689 					printFunc("\"%s\"\n", (char*)data);
690 					break;
691 				default:
692 					printFunc("data at %p, %ld bytes\n", (char*)data, size);
693 					break;
694 			}
695 			if (isIntType)
696 				printFunc("%lld (0x%llx)\n", intData, intData);
697 		}
698 	}
699 }
700 
701 
702 KMessage::Header*
703 KMessage::_Header() const
704 {
705 	return (Header*)fBuffer;
706 }
707 
708 
709 int32
710 KMessage::_BufferOffsetFor(const void* data) const
711 {
712 	if (!data)
713 		return -1;
714 	return (uint8*)data - (uint8*)fBuffer;
715 }
716 
717 
718 KMessage::FieldHeader*
719 KMessage::_FirstFieldHeader() const
720 {
721 	return (FieldHeader*)_Align(fBuffer, sizeof(Header));
722 }
723 
724 
725 KMessage::FieldHeader*
726 KMessage::_LastFieldHeader() const
727 {
728 	return _FieldHeaderForOffset(fLastFieldOffset);
729 }
730 
731 
732 KMessage::FieldHeader*
733 KMessage::_FieldHeaderForOffset(int32 offset) const
734 {
735 	if (offset <= 0 || offset >= _Header()->size)
736 		return NULL;
737 	return (FieldHeader*)((uint8*)fBuffer + offset);
738 }
739 
740 
741 status_t
742 KMessage::_AddField(const char* name, type_code type, int32 elementSize,
743 	KMessageField* field)
744 {
745 	FieldHeader* fieldHeader;
746 	int32 alignedSize;
747 	status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true,
748 		true, (void**)&fieldHeader, &alignedSize);
749 	if (error != B_OK)
750 		return error;
751 	fieldHeader->type = type;
752 	fieldHeader->elementSize = elementSize;
753 	fieldHeader->elementCount = 0;
754 	fieldHeader->fieldSize = alignedSize;
755 	fieldHeader->headerSize = alignedSize;
756 	strcpy(fieldHeader->name, name);
757 	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
758 	if (field)
759 		field->SetTo(this, _BufferOffsetFor(fieldHeader));
760 	return B_OK;
761 }
762 
763 
764 status_t
765 KMessage::_AddFieldData(KMessageField* field, const void* data,
766 	int32 elementSize, int32 elementCount)
767 {
768 	if (!field)
769 		return B_BAD_VALUE;
770 	FieldHeader* fieldHeader = field->_Header();
771 	FieldHeader* lastField = _LastFieldHeader();
772 	if (!fieldHeader || fieldHeader != lastField || !data
773 		|| elementSize < 0 || elementCount < 0) {
774 		return B_BAD_VALUE;
775 	}
776 	if (elementCount == 0)
777 		return B_OK;
778 	// fixed size values
779 	if (fieldHeader->HasFixedElementSize()) {
780 		if (elementSize != fieldHeader->elementSize)
781 			return B_BAD_VALUE;
782 		void* address;
783 		int32 alignedSize;
784 		status_t error = _AllocateSpace(elementSize * elementCount,
785 			(fieldHeader->elementCount == 0), false, &address, &alignedSize);
786 		if (error != B_OK)
787 			return error;
788 		fieldHeader = field->_Header();	// might have been relocated
789 		memcpy(address, data, elementSize * elementCount);
790 		fieldHeader->elementCount += elementCount;
791 		fieldHeader->fieldSize = (uint8*)address + alignedSize
792 			- (uint8*)fieldHeader;
793 		return B_OK;
794 	}
795 	// non-fixed size values
796 	// add the elements individually (TODO: Optimize!)
797 	int32 valueHeaderSize = _Align(sizeof(FieldValueHeader));
798 	int32 entrySize = valueHeaderSize + elementSize;
799 	for (int32 i = 0; i < elementCount; i++) {
800 		void* address;
801 		int32 alignedSize;
802 		status_t error = _AllocateSpace(entrySize, true, false, &address,
803 			&alignedSize);
804 		if (error != B_OK)
805 			return error;
806 		fieldHeader = field->_Header();	// might have been relocated
807 		FieldValueHeader* valueHeader = (FieldValueHeader*)address;
808 		valueHeader->size = elementSize;
809 		memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize,
810 			elementSize);
811 		fieldHeader->elementCount++;
812 		fieldHeader->fieldSize = (uint8*)address + alignedSize
813 			- (uint8*)fieldHeader;
814 	}
815 	return B_OK;
816 }
817 
818 
819 status_t
820 KMessage::_InitFromBuffer(bool sizeFromBuffer)
821 {
822 	if (fBuffer == NULL)
823 		return B_BAD_DATA;
824 
825 	// clone the buffer, if requested
826 	if ((fFlags & KMESSAGE_CLONE_BUFFER) != 0 || _Align(fBuffer) != fBuffer) {
827 		if (sizeFromBuffer) {
828 			int32 size = fBufferCapacity;
829 			memcpy(&size, &_Header()->size, 4);
830 			fBufferCapacity = size;
831 		}
832 
833 		void* buffer = memalign(kMessageBufferAlignment, fBufferCapacity);
834 		if (buffer == NULL)
835 			return B_NO_MEMORY;
836 
837 		memcpy(buffer, fBuffer, fBufferCapacity);
838 
839 		if ((fFlags & KMESSAGE_CLONE_BUFFER) == 0)
840 			free(fBuffer);
841 
842 		fBuffer = buffer;
843 		fFlags &= ~(uint32)(KMESSAGE_READ_ONLY | KMESSAGE_CLONE_BUFFER);
844 	}
845 
846 	if (_Align(fBuffer) != fBuffer)
847 		return B_BAD_DATA;
848 
849 	Header* header = _Header();
850 
851 	if (sizeFromBuffer)
852 		fBufferCapacity = header->size;
853 
854 	if (fBufferCapacity < (int)sizeof(Header))
855 		return B_BAD_DATA;
856 
857 	// check header
858 	if (header->magic != kMessageHeaderMagic)
859 		return B_BAD_DATA;
860 	if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity)
861 		return B_BAD_DATA;
862 
863 	// check the fields
864 	FieldHeader* fieldHeader = NULL;
865 	uint8* data = (uint8*)_FirstFieldHeader();
866 	int32 remainingBytes = (uint8*)fBuffer + header->size - data;
867 	while (remainingBytes > 0) {
868 		if (remainingBytes < (int)sizeof(FieldHeader))
869 			return B_BAD_DATA;
870 		fieldHeader = (FieldHeader*)data;
871 		// check field header
872 		if (fieldHeader->type == B_ANY_TYPE)
873 			return B_BAD_DATA;
874 		if (fieldHeader->elementCount < 0)
875 			return B_BAD_DATA;
876 		if (fieldHeader->fieldSize < (int)sizeof(FieldHeader)
877 			|| fieldHeader->fieldSize > remainingBytes) {
878 			return B_BAD_DATA;
879 		}
880 		if (fieldHeader->headerSize < (int)sizeof(FieldHeader)
881 			|| fieldHeader->headerSize > fieldHeader->fieldSize) {
882 			return B_BAD_DATA;
883 		}
884 		int32 maxNameLen = data + fieldHeader->headerSize
885 			- (uint8*)fieldHeader->name;
886 		int32 nameLen = strnlen(fieldHeader->name, maxNameLen);
887 		if (nameLen == maxNameLen || nameLen == 0)
888 			return B_BAD_DATA;
889 		int32 fieldSize =  fieldHeader->headerSize;
890 		if (fieldHeader->HasFixedElementSize()) {
891 			// fixed element size
892 			int32 dataSize = fieldHeader->elementSize
893 				* fieldHeader->elementCount;
894 			fieldSize = (uint8*)fieldHeader->Data() + dataSize - data;
895 		} else {
896 			// non-fixed element size
897 			FieldValueHeader* valueHeader
898 				= (FieldValueHeader*)fieldHeader->Data();
899 			for (int32 i = 0; i < fieldHeader->elementCount; i++) {
900 				remainingBytes = (uint8*)fBuffer + header->size
901 					- (uint8*)valueHeader;
902 				if (remainingBytes < (int)sizeof(FieldValueHeader))
903 					return B_BAD_DATA;
904 				uint8* value = (uint8*)valueHeader->Data();
905 				remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value;
906 				if (remainingBytes < valueHeader->size)
907 					return B_BAD_DATA;
908 				fieldSize = value + valueHeader->size - data;
909 				valueHeader = valueHeader->NextFieldValueHeader();
910 			}
911 			if (fieldSize > fieldHeader->fieldSize)
912 				return B_BAD_DATA;
913 		}
914 		data = (uint8*)fieldHeader->NextFieldHeader();
915 		remainingBytes = (uint8*)fBuffer + header->size - data;
916 	}
917 	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
918 	return B_OK;
919 }
920 
921 
922 void
923 KMessage::_InitBuffer(uint32 what)
924 {
925 	Header* header = _Header();
926 	header->magic = kMessageHeaderMagic;
927 	header->size = sizeof(Header);
928 	header->what = what;
929 	header->sender = -1;
930 	header->targetToken = -1;
931 	header->replyPort = -1;
932 	header->replyToken = -1;
933 	fLastFieldOffset = 0;
934 }
935 
936 
937 void
938 KMessage::_CheckBuffer()
939 {
940 	int32 lastFieldOffset = fLastFieldOffset;
941 	if (_InitFromBuffer(false) != B_OK) {
942 		PANIC("internal data mangled");
943 	}
944 	if (fLastFieldOffset != lastFieldOffset) {
945 		PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()");
946 	}
947 }
948 
949 
950 status_t
951 KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize,
952 	void** address, int32* alignedSize)
953 {
954 	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
955 		return B_NOT_ALLOWED;
956 
957 	int32 offset = ContentSize();
958 	if (alignAddress)
959 		offset = _Align(offset);
960 	int32 newSize = offset + size;
961 	if (alignSize)
962 		newSize = _Align(newSize);
963 	// reallocate if necessary
964 	if (fBuffer == &fHeader) {
965 		int32 newCapacity = _CapacityFor(newSize);
966 		void* newBuffer = memalign(kMessageBufferAlignment, newCapacity);
967 		if (!newBuffer)
968 			return B_NO_MEMORY;
969 		fBuffer = newBuffer;
970 		fBufferCapacity = newCapacity;
971 		fFlags |= KMESSAGE_OWNS_BUFFER;
972 		memcpy(fBuffer, &fHeader, sizeof(fHeader));
973 	} else {
974 		if (newSize > fBufferCapacity) {
975 			// if we don't own the buffer, we can't resize it
976 			if (!(fFlags & KMESSAGE_OWNS_BUFFER)) {
977 #if defined(_KERNEL_MODE) && 0
978 				// optional debugging to find insufficiently sized KMessage
979 				// buffers (e.g. for in-kernel notifications)
980 				panic("KMessage: out of space: available: %" B_PRId32
981 					", needed: %" B_PRId32 "\n", fBufferCapacity, newSize);
982 #endif
983 				return B_BUFFER_OVERFLOW;
984 			}
985 
986 			int32 newCapacity = _CapacityFor(newSize);
987 			void* newBuffer = realloc(fBuffer, newCapacity);
988 			if (!newBuffer)
989 				return B_NO_MEMORY;
990 			fBuffer = newBuffer;
991 			fBufferCapacity = newCapacity;
992 		}
993 	}
994 	_Header()->size = newSize;
995 	*address = (char*)fBuffer + offset;
996 	*alignedSize = newSize - offset;
997 	return B_OK;
998 }
999 
1000 
1001 int32
1002 KMessage::_CapacityFor(int32 size)
1003 {
1004 	return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
1005 		* kMessageReallocChunkSize;
1006 }
1007 
1008 
1009 // #pragma mark - KMessageField
1010 
1011 
1012 KMessageField::KMessageField()
1013 	:
1014 	fMessage(NULL),
1015 	fHeaderOffset(0)
1016 {
1017 }
1018 
1019 
1020 void
1021 KMessageField::Unset()
1022 {
1023 	fMessage = NULL;
1024 	fHeaderOffset = 0;
1025 }
1026 
1027 
1028 KMessage*
1029 KMessageField::Message() const
1030 {
1031 	return fMessage;
1032 }
1033 
1034 
1035 const char*
1036 KMessageField::Name() const
1037 {
1038 	KMessage::FieldHeader* header = _Header();
1039 	return header ? header->name : NULL;
1040 }
1041 
1042 
1043 type_code
1044 KMessageField::TypeCode() const
1045 {
1046 	KMessage::FieldHeader* header = _Header();
1047 	return header ? header->type : 0;
1048 }
1049 
1050 
1051 bool
1052 KMessageField::HasFixedElementSize() const
1053 {
1054 	KMessage::FieldHeader* header = _Header();
1055 	return header ? header->HasFixedElementSize() : false;
1056 }
1057 
1058 
1059 int32
1060 KMessageField::ElementSize() const
1061 {
1062 	KMessage::FieldHeader* header = _Header();
1063 	return header ? header->elementSize : -1;
1064 }
1065 
1066 
1067 status_t
1068 KMessageField::AddElement(const void* data, int32 size)
1069 {
1070 	KMessage::FieldHeader* header = _Header();
1071 	if (!header || !data)
1072 		return B_BAD_VALUE;
1073 	if (size < 0) {
1074 		size = ElementSize();
1075 		if (size < 0)
1076 			return B_BAD_VALUE;
1077 	}
1078 	return fMessage->_AddFieldData(this, data, size, 1);
1079 }
1080 
1081 
1082 status_t
1083 KMessageField::AddElements(const void* data, int32 count, int32 elementSize)
1084 {
1085 	KMessage::FieldHeader* header = _Header();
1086 	if (!header || !data || count < 0)
1087 		return B_BAD_VALUE;
1088 	if (elementSize < 0) {
1089 		elementSize = ElementSize();
1090 		if (elementSize < 0)
1091 			return B_BAD_VALUE;
1092 	}
1093 	return fMessage->_AddFieldData(this, data, elementSize, count);
1094 }
1095 
1096 
1097 const void*
1098 KMessageField::ElementAt(int32 index, int32* size) const
1099 {
1100 	KMessage::FieldHeader* header = _Header();
1101 	return header ? header->ElementAt(index, size) : NULL;
1102 }
1103 
1104 
1105 int32
1106 KMessageField::CountElements() const
1107 {
1108 	KMessage::FieldHeader* header = _Header();
1109 	return header ? header->elementCount : 0;
1110 }
1111 
1112 
1113 void
1114 KMessageField::SetTo(KMessage* message, int32 headerOffset)
1115 {
1116 	fMessage = message;
1117 	fHeaderOffset = headerOffset;
1118 }
1119 
1120 
1121 KMessage::FieldHeader*
1122 KMessageField::_Header() const
1123 {
1124 	return fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL;
1125 }
1126