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