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