xref: /haiku/src/system/kernel/messaging/KMessage.cpp (revision d9cebac2b77547b7064f22497514eecd2d047160)
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 <util/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) || defined(_LOADER_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 // SetDeliveryInfo
440 void
441 KMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort,
442 	int32 replyToken, team_id senderTeam)
443 {
444 	Header* header = _Header();
445 	header->sender = senderTeam;
446 	header->targetToken = targetToken;
447 	header->replyPort = replyPort;
448 	header->replyToken = replyToken;
449 	header->sender = senderTeam;
450 }
451 
452 #ifndef KMESSAGE_CONTAINER_ONLY
453 
454 // SendTo
455 status_t
456 KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort,
457 	int32 replyToken, bigtime_t timeout, team_id senderTeam)
458 {
459 	// get the sender team
460 	if (senderTeam < 0) {
461 		thread_info info;
462 		status_t error = get_thread_info(find_thread(NULL), &info);
463 		if (error != B_OK)
464 			return error;
465 
466 		senderTeam = info.team;
467 	}
468 
469 	SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam);
470 
471 	// send the message
472 	if (timeout < 0)
473 		return write_port(targetPort, 'KMSG', fBuffer, ContentSize());
474 
475 	return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(),
476 		B_RELATIVE_TIMEOUT, timeout);
477 }
478 
479 // SendTo
480 status_t
481 KMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply,
482 	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
483 {
484 	// get the team the target port belongs to
485 	port_info portInfo;
486 	status_t error = get_port_info(targetPort, &portInfo);
487 	if (error != B_OK)
488 		return error;
489 	team_id targetTeam = portInfo.team;
490 	// allocate a reply port, if a reply is desired
491 	port_id replyPort = -1;
492 	if (reply) {
493 		// get our team
494 		team_id ourTeam = B_SYSTEM_TEAM;
495 		#ifndef _KERNEL_MODE
496 			if (targetTeam != B_SYSTEM_TEAM) {
497 				thread_info threadInfo;
498 				error = get_thread_info(find_thread(NULL), &threadInfo);
499 				if (error != B_OK)
500 					return error;
501 				ourTeam = threadInfo.team;
502 			}
503 		#endif
504 		// create the port
505 		replyPort = create_port(1, "KMessage reply port");
506 		if (replyPort < 0)
507 			return replyPort;
508 		// If the target team is not our team and not the kernel team either,
509 		// we transfer the ownership of the port to it, so we will not block
510 		if (targetTeam != ourTeam && targetTeam != B_SYSTEM_TEAM)
511 			set_port_owner(replyPort, targetTeam);
512 	}
513 	struct PortDeleter {
514 		PortDeleter(port_id port) : port(port) {}
515 		~PortDeleter()
516 		{
517 			if (port >= 0)
518 				delete_port(port);
519 		}
520 
521 		port_id	port;
522 	} replyPortDeleter(replyPort);
523 	// send the message
524 	error = SendTo(targetPort, targetToken, replyPort, 0,
525 		deliveryTimeout, senderTeam);
526 	if (error != B_OK)
527 		return error;
528 	// get the reply
529 	if (reply)
530 		return reply->ReceiveFrom(replyPort, replyTimeout);
531 	return B_OK;
532 }
533 
534 // SendReply
535 status_t
536 KMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken,
537 	bigtime_t timeout, team_id senderTeam)
538 {
539 	if (!message)
540 		return B_BAD_VALUE;
541 	return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken,
542 		timeout, senderTeam);
543 }
544 
545 // SendReply
546 status_t
547 KMessage::SendReply(KMessage* message, KMessage* reply,
548 	bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
549 {
550 	if (!message)
551 		return B_BAD_VALUE;
552 	return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout,
553 		replyTimeout, senderTeam);
554 }
555 
556 // ReceiveFrom
557 status_t
558 KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout)
559 {
560 	// get the port buffer size
561 	ssize_t size;
562 	if (timeout < 0)
563 		size = port_buffer_size(fromPort);
564 	else
565 		size = port_buffer_size_etc(fromPort, B_RELATIVE_TIMEOUT, timeout);
566 	if (size < 0)
567 		return size;
568 	// allocate a buffer
569 	uint8* buffer = (uint8*)malloc(size);
570 	if (!buffer)
571 		return B_NO_MEMORY;
572 	// read the message
573 	int32 what;
574 	ssize_t realSize = read_port_etc(fromPort, &what, buffer, size,
575 		B_RELATIVE_TIMEOUT, 0);
576 	if (realSize < 0)
577 		return realSize;
578 	if (size != realSize)
579 		return B_ERROR;
580 	// init the message
581 	return SetTo(buffer, size, 0,
582 		KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER);
583 }
584 
585 #endif	// !KMESSAGE_CONTAINER_ONLY
586 
587 
588 // _Header
589 KMessage::Header *
590 KMessage::_Header() const
591 {
592 	return (Header*)fBuffer;
593 }
594 
595 // _BufferOffsetFor
596 int32
597 KMessage::_BufferOffsetFor(const void* data) const
598 {
599 	if (!data)
600 		return -1;
601 	return ((uint8*)data - (uint8*)fBuffer);
602 }
603 
604 // _FirstFieldHeader
605 KMessage::FieldHeader *
606 KMessage::_FirstFieldHeader() const
607 {
608 	return (FieldHeader*)_Align(fBuffer, sizeof(Header));
609 }
610 
611 // _LastFieldHeader
612 KMessage::FieldHeader *
613 KMessage::_LastFieldHeader() const
614 {
615 	return _FieldHeaderForOffset(fLastFieldOffset);
616 }
617 
618 // _FieldHeaderForOffset
619 KMessage::FieldHeader *
620 KMessage::_FieldHeaderForOffset(int32 offset) const
621 {
622 	if (offset <= 0 || offset >= _Header()->size)
623 		return NULL;
624 	return (FieldHeader*)((uint8*)fBuffer + offset);
625 }
626 
627 // _AddField
628 status_t
629 KMessage::_AddField(const char *name, type_code type, int32 elementSize,
630 	KMessageField *field)
631 {
632 	FieldHeader *fieldHeader;
633 	int32 alignedSize;
634 	status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true,
635 		true, (void**)&fieldHeader, &alignedSize);
636 	if (error != B_OK)
637 		return error;
638 	fieldHeader->type = type;
639 	fieldHeader->elementSize = elementSize;
640 	fieldHeader->elementCount = 0;
641 	fieldHeader->fieldSize = alignedSize;
642 	fieldHeader->headerSize = alignedSize;
643 	strcpy(fieldHeader->name, name);
644 	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
645 	if (field)
646 		field->SetTo(this, _BufferOffsetFor(fieldHeader));
647 	return B_OK;
648 }
649 
650 // _AddFieldData
651 status_t
652 KMessage::_AddFieldData(KMessageField *field, const void *data,
653 	int32 elementSize, int32 elementCount)
654 {
655 	if (!field)
656 		return B_BAD_VALUE;
657 	FieldHeader *fieldHeader = field->_Header();
658 	FieldHeader* lastField = _LastFieldHeader();
659 	if (!fieldHeader || fieldHeader != lastField || !data
660 		|| elementSize < 0 || elementCount < 0) {
661 		return B_BAD_VALUE;
662 	}
663 	if (elementCount == 0)
664 		return B_OK;
665 	// fixed size values
666 	if (fieldHeader->HasFixedElementSize()) {
667 		if (elementSize != fieldHeader->elementSize)
668 			return B_BAD_VALUE;
669 		void *address;
670 		int32 alignedSize;
671 		status_t error = _AllocateSpace(elementSize * elementCount,
672 			(fieldHeader->elementCount == 0), false, &address, &alignedSize);
673 		if (error != B_OK)
674 			return error;
675 		fieldHeader = field->_Header();	// might have been relocated
676 		memcpy(address, data, elementSize * elementCount);
677 		fieldHeader->elementCount += elementCount;
678 		fieldHeader->fieldSize = (uint8*)address + alignedSize
679 			- (uint8*)fieldHeader;
680 		return B_OK;
681 	}
682 	// non-fixed size values
683 	// add the elements individually (TODO: Optimize!)
684 	int32 valueHeaderSize = _Align(sizeof(FieldValueHeader));
685 	int32 entrySize = valueHeaderSize + elementSize;
686 	for (int32 i = 0; i < elementCount; i++) {
687 		void *address;
688 		int32 alignedSize;
689 		status_t error = _AllocateSpace(entrySize, true, false, &address,
690 			&alignedSize);
691 		if (error != B_OK)
692 			return error;
693 		fieldHeader = field->_Header();	// might have been relocated
694 		FieldValueHeader *valueHeader = (FieldValueHeader*)address;
695 		valueHeader->size = elementSize;
696 		memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize,
697 			elementSize);
698 		fieldHeader->elementCount++;
699 		fieldHeader->fieldSize = (uint8*)address + alignedSize
700 			- (uint8*)fieldHeader;
701 	}
702 	return B_OK;
703 }
704 
705 // _InitFromBuffer
706 status_t
707 KMessage::_InitFromBuffer(bool sizeFromBuffer)
708 {
709 	if (!fBuffer || _Align(fBuffer) != fBuffer)
710 		return B_BAD_DATA;
711 	Header *header = _Header();
712 
713 	if (sizeFromBuffer)
714 		fBufferCapacity = header->size;
715 
716 	if (fBufferCapacity < (int)sizeof(Header))
717 		return B_BAD_DATA;
718 
719 	// check header
720 	if (header->magic != kMessageHeaderMagic)
721 		return B_BAD_DATA;
722 	if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity)
723 		return B_BAD_DATA;
724 
725 	// check the fields
726 	FieldHeader *fieldHeader = NULL;
727 	uint8 *data = (uint8*)_FirstFieldHeader();
728 	int32 remainingBytes = (uint8*)fBuffer + header->size - data;
729 	while (remainingBytes > 0) {
730 		if (remainingBytes < (int)sizeof(FieldHeader))
731 			return B_BAD_DATA;
732 		fieldHeader = (FieldHeader*)data;
733 		// check field header
734 		if (fieldHeader->type == B_ANY_TYPE)
735 			return B_BAD_DATA;
736 		if (fieldHeader->elementCount < 0)
737 			return B_BAD_DATA;
738 		if (fieldHeader->fieldSize < (int)sizeof(FieldHeader)
739 			|| fieldHeader->fieldSize > remainingBytes) {
740 			return B_BAD_DATA;
741 		}
742 		if (fieldHeader->headerSize < (int)sizeof(FieldHeader)
743 			|| fieldHeader->headerSize > fieldHeader->fieldSize) {
744 			return B_BAD_DATA;
745 		}
746 		int32 maxNameLen = data + fieldHeader->headerSize
747 			- (uint8*)fieldHeader->name;
748 		int32 nameLen = strnlen(fieldHeader->name, maxNameLen);
749 		if (nameLen == maxNameLen || nameLen == 0)
750 			return B_BAD_DATA;
751 		int32 fieldSize =  fieldHeader->headerSize;
752 		if (fieldHeader->HasFixedElementSize()) {
753 			// fixed element size
754 			int32 dataSize = fieldHeader->elementSize
755 				* fieldHeader->elementCount;
756 			fieldSize = (uint8*)fieldHeader->Data() + dataSize - data;
757 		} else {
758 			// non-fixed element size
759 			FieldValueHeader *valueHeader
760 				= (FieldValueHeader *)fieldHeader->Data();
761 			for (int32 i = 0; i < fieldHeader->elementCount; i++) {
762 				remainingBytes = (uint8*)fBuffer + header->size
763 					- (uint8*)valueHeader;
764 				if (remainingBytes < (int)sizeof(FieldValueHeader))
765 					return B_BAD_DATA;
766 				uint8 *value = (uint8*)valueHeader->Data();
767 				remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value;
768 				if (remainingBytes < valueHeader->size)
769 					return B_BAD_DATA;
770 				fieldSize = value + valueHeader->size - data;
771 				valueHeader = valueHeader->NextFieldValueHeader();
772 			}
773 			if (fieldSize > fieldHeader->fieldSize)
774 				return B_BAD_DATA;
775 		}
776 		data = (uint8*)fieldHeader->NextFieldHeader();
777 		remainingBytes = (uint8*)fBuffer + header->size - data;
778 	}
779 	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
780 	return B_OK;
781 }
782 
783 // _InitBuffer
784 void
785 KMessage::_InitBuffer(uint32 what)
786 {
787 	Header *header = _Header();
788 	header->magic = kMessageHeaderMagic;
789 	header->size = sizeof(Header);
790 	header->what = what;
791 	header->sender = -1;
792 	header->targetToken = -1;
793 	header->replyPort = -1;
794 	header->replyToken = -1;
795 	fLastFieldOffset = 0;
796 }
797 
798 // _CheckBuffer
799 void
800 KMessage::_CheckBuffer()
801 {
802 	int32 lastFieldOffset = fLastFieldOffset;
803 	if (_InitFromBuffer(false) != B_OK) {
804 		PANIC("internal data mangled");
805 	}
806 	if (fLastFieldOffset != lastFieldOffset) {
807 		PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()");
808 	}
809 }
810 
811 // _AllocateSpace
812 status_t
813 KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize,
814 	void **address, int32 *alignedSize)
815 {
816 	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
817 		return B_NOT_ALLOWED;
818 
819 	int32 offset = ContentSize();
820 	if (alignAddress)
821 		offset = _Align(offset);
822 	int32 newSize = offset + size;
823 	if (alignSize)
824 		newSize = _Align(newSize);
825 	// reallocate if necessary
826 	if (fBuffer == &fHeader) {
827 		int32 newCapacity = _CapacityFor(newSize);
828 		void *newBuffer = malloc(newCapacity);
829 		if (!newBuffer)
830 			return B_NO_MEMORY;
831 		fBuffer = newBuffer;
832 		fBufferCapacity = newCapacity;
833 		fFlags |= KMESSAGE_OWNS_BUFFER;
834 		memcpy(fBuffer, &fHeader, sizeof(fHeader));
835 	} else {
836 		if (newSize > fBufferCapacity) {
837 			// if we don't own the buffer, we can't resize it
838 			if (!(fFlags & KMESSAGE_OWNS_BUFFER))
839 				return B_BUFFER_OVERFLOW;
840 			int32 newCapacity = _CapacityFor(newSize);
841 			void *newBuffer = realloc(fBuffer, newCapacity);
842 			if (!newBuffer)
843 				return B_NO_MEMORY;
844 			fBuffer = newBuffer;
845 			fBufferCapacity = newCapacity;
846 		}
847 	}
848 	_Header()->size = newSize;
849 	*address = (char*)fBuffer + offset;
850 	*alignedSize = newSize - offset;
851 	return B_OK;
852 }
853 
854 // _CapacityFor
855 int32
856 KMessage::_CapacityFor(int32 size)
857 {
858 	return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
859 		* kMessageReallocChunkSize;
860 }
861 
862 
863 // #pragma mark -
864 
865 // constructor
866 KMessageField::KMessageField()
867 	: fMessage(NULL),
868 	  fHeaderOffset(0)
869 {
870 }
871 
872 // Unset
873 void
874 KMessageField::Unset()
875 {
876 	fMessage = NULL;
877 	fHeaderOffset = 0;
878 }
879 
880 // Message
881 KMessage *
882 KMessageField::Message() const
883 {
884 	return fMessage;
885 }
886 
887 // Name
888 const char *
889 KMessageField::Name() const
890 {
891 	KMessage::FieldHeader* header = _Header();
892 	return (header ? header->name : NULL);
893 }
894 
895 // TypeCode
896 type_code
897 KMessageField::TypeCode() const
898 {
899 	KMessage::FieldHeader* header = _Header();
900 	return (header ? header->type : 0);
901 }
902 
903 // HasFixedElementSize
904 bool
905 KMessageField::HasFixedElementSize() const
906 {
907 	KMessage::FieldHeader* header = _Header();
908 	return (header ? header->HasFixedElementSize() : false);
909 }
910 
911 // ElementSize
912 int32
913 KMessageField::ElementSize() const
914 {
915 	KMessage::FieldHeader* header = _Header();
916 	return (header ? header->elementSize : -1);
917 }
918 
919 // AddElement
920 status_t
921 KMessageField::AddElement(const void *data, int32 size)
922 {
923 	KMessage::FieldHeader* header = _Header();
924 	if (!header || !data)
925 		return B_BAD_VALUE;
926 	if (size < 0) {
927 		size = ElementSize();
928 		if (size < 0)
929 			return B_BAD_VALUE;
930 	}
931 	return fMessage->_AddFieldData(this, data, size, 1);
932 }
933 
934 // AddElements
935 status_t
936 KMessageField::AddElements(const void *data, int32 count, int32 elementSize)
937 {
938 	KMessage::FieldHeader* header = _Header();
939 	if (!header || !data || count < 0)
940 		return B_BAD_VALUE;
941 	if (elementSize < 0) {
942 		elementSize = ElementSize();
943 		if (elementSize < 0)
944 			return B_BAD_VALUE;
945 	}
946 	return fMessage->_AddFieldData(this, data, elementSize, count);
947 }
948 
949 // ElementAt
950 const void *
951 KMessageField::ElementAt(int32 index, int32 *size) const
952 {
953 	KMessage::FieldHeader* header = _Header();
954 	return (header ? header->ElementAt(index, size) : NULL);
955 }
956 
957 // CountElements
958 int32
959 KMessageField::CountElements() const
960 {
961 	KMessage::FieldHeader* header = _Header();
962 	return (header ? header->elementCount : 0);
963 }
964 
965 // SetTo
966 void
967 KMessageField::SetTo(KMessage *message, int32 headerOffset)
968 {
969 	fMessage = message;
970 	fHeaderOffset = headerOffset;
971 }
972 
973 // _GetHeader
974 KMessage::FieldHeader*
975 KMessageField::_Header() const
976 {
977 	return (fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL);
978 }
979 
980