xref: /haiku/src/system/kernel/messaging/KMessage.cpp (revision 2d9a40222fccb7e7e1461d40cb4b0e39003a3b8e)
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 
557 // ReceiveFrom
558 status_t
559 KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout,
560 	port_message_info* messageInfo)
561 {
562 	port_message_info _messageInfo;
563 	if (messageInfo == NULL)
564 		messageInfo = &_messageInfo;
565 
566 	// get the port buffer size
567 	status_t error;
568 	if (timeout < 0) {
569 		error = get_port_message_info_etc(fromPort, messageInfo, 0, 0);
570 	} else {
571 		error = get_port_message_info_etc(fromPort, messageInfo,
572 			B_RELATIVE_TIMEOUT, timeout);
573 	}
574 	if (error != B_OK)
575 		return error;
576 
577 	// allocate a buffer
578 	uint8* buffer = (uint8*)malloc(messageInfo->size);
579 	if (!buffer)
580 		return B_NO_MEMORY;
581 
582 	// read the message
583 	int32 what;
584 	ssize_t realSize = read_port_etc(fromPort, &what, buffer, messageInfo->size,
585 		B_RELATIVE_TIMEOUT, 0);
586 	if (realSize < 0)
587 		return realSize;
588 	if (messageInfo->size != (size_t)realSize)
589 		return B_ERROR;
590 
591 	// init the message
592 	return SetTo(buffer, messageInfo->size, 0,
593 		KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER);
594 }
595 
596 #endif	// !KMESSAGE_CONTAINER_ONLY
597 
598 
599 void
600 KMessage::Dump(void (*printFunc)(const char*,...))
601 {
602 	Header* header = _Header();
603 	printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: 0x0lx\n",
604 		fBuffer, header->size, fBufferCapacity, fFlags);
605 
606 	KMessageField field;
607 	while (GetNextField(&field) == B_OK) {
608 		type_code type = field.TypeCode();
609 		int32 count = field.CountElements();
610 		printFunc("  field: %-20s: type: 0x%lx ('%c%c%c%c'), %ld element%s\n",
611 			field.Name(), type, (char)(type >> 24), (char)(type >> 16),
612 			(char)(type >> 8), (char)type, count, count == 1 ? "" : "s");
613 	}
614 }
615 
616 
617 // _Header
618 KMessage::Header *
619 KMessage::_Header() const
620 {
621 	return (Header*)fBuffer;
622 }
623 
624 // _BufferOffsetFor
625 int32
626 KMessage::_BufferOffsetFor(const void* data) const
627 {
628 	if (!data)
629 		return -1;
630 	return ((uint8*)data - (uint8*)fBuffer);
631 }
632 
633 // _FirstFieldHeader
634 KMessage::FieldHeader *
635 KMessage::_FirstFieldHeader() const
636 {
637 	return (FieldHeader*)_Align(fBuffer, sizeof(Header));
638 }
639 
640 // _LastFieldHeader
641 KMessage::FieldHeader *
642 KMessage::_LastFieldHeader() const
643 {
644 	return _FieldHeaderForOffset(fLastFieldOffset);
645 }
646 
647 // _FieldHeaderForOffset
648 KMessage::FieldHeader *
649 KMessage::_FieldHeaderForOffset(int32 offset) const
650 {
651 	if (offset <= 0 || offset >= _Header()->size)
652 		return NULL;
653 	return (FieldHeader*)((uint8*)fBuffer + offset);
654 }
655 
656 // _AddField
657 status_t
658 KMessage::_AddField(const char *name, type_code type, int32 elementSize,
659 	KMessageField *field)
660 {
661 	FieldHeader *fieldHeader;
662 	int32 alignedSize;
663 	status_t error = _AllocateSpace(sizeof(FieldHeader) + strlen(name), true,
664 		true, (void**)&fieldHeader, &alignedSize);
665 	if (error != B_OK)
666 		return error;
667 	fieldHeader->type = type;
668 	fieldHeader->elementSize = elementSize;
669 	fieldHeader->elementCount = 0;
670 	fieldHeader->fieldSize = alignedSize;
671 	fieldHeader->headerSize = alignedSize;
672 	strcpy(fieldHeader->name, name);
673 	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
674 	if (field)
675 		field->SetTo(this, _BufferOffsetFor(fieldHeader));
676 	return B_OK;
677 }
678 
679 // _AddFieldData
680 status_t
681 KMessage::_AddFieldData(KMessageField *field, const void *data,
682 	int32 elementSize, int32 elementCount)
683 {
684 	if (!field)
685 		return B_BAD_VALUE;
686 	FieldHeader *fieldHeader = field->_Header();
687 	FieldHeader* lastField = _LastFieldHeader();
688 	if (!fieldHeader || fieldHeader != lastField || !data
689 		|| elementSize < 0 || elementCount < 0) {
690 		return B_BAD_VALUE;
691 	}
692 	if (elementCount == 0)
693 		return B_OK;
694 	// fixed size values
695 	if (fieldHeader->HasFixedElementSize()) {
696 		if (elementSize != fieldHeader->elementSize)
697 			return B_BAD_VALUE;
698 		void *address;
699 		int32 alignedSize;
700 		status_t error = _AllocateSpace(elementSize * elementCount,
701 			(fieldHeader->elementCount == 0), false, &address, &alignedSize);
702 		if (error != B_OK)
703 			return error;
704 		fieldHeader = field->_Header();	// might have been relocated
705 		memcpy(address, data, elementSize * elementCount);
706 		fieldHeader->elementCount += elementCount;
707 		fieldHeader->fieldSize = (uint8*)address + alignedSize
708 			- (uint8*)fieldHeader;
709 		return B_OK;
710 	}
711 	// non-fixed size values
712 	// add the elements individually (TODO: Optimize!)
713 	int32 valueHeaderSize = _Align(sizeof(FieldValueHeader));
714 	int32 entrySize = valueHeaderSize + elementSize;
715 	for (int32 i = 0; i < elementCount; i++) {
716 		void *address;
717 		int32 alignedSize;
718 		status_t error = _AllocateSpace(entrySize, true, false, &address,
719 			&alignedSize);
720 		if (error != B_OK)
721 			return error;
722 		fieldHeader = field->_Header();	// might have been relocated
723 		FieldValueHeader *valueHeader = (FieldValueHeader*)address;
724 		valueHeader->size = elementSize;
725 		memcpy(valueHeader->Data(), (const uint8*)data + i * elementSize,
726 			elementSize);
727 		fieldHeader->elementCount++;
728 		fieldHeader->fieldSize = (uint8*)address + alignedSize
729 			- (uint8*)fieldHeader;
730 	}
731 	return B_OK;
732 }
733 
734 // _InitFromBuffer
735 status_t
736 KMessage::_InitFromBuffer(bool sizeFromBuffer)
737 {
738 	if (!fBuffer || _Align(fBuffer) != fBuffer)
739 		return B_BAD_DATA;
740 	Header *header = _Header();
741 
742 	if (sizeFromBuffer)
743 		fBufferCapacity = header->size;
744 
745 	if (fBufferCapacity < (int)sizeof(Header))
746 		return B_BAD_DATA;
747 
748 	// check header
749 	if (header->magic != kMessageHeaderMagic)
750 		return B_BAD_DATA;
751 	if (header->size < (int)sizeof(Header) || header->size > fBufferCapacity)
752 		return B_BAD_DATA;
753 
754 	// check the fields
755 	FieldHeader *fieldHeader = NULL;
756 	uint8 *data = (uint8*)_FirstFieldHeader();
757 	int32 remainingBytes = (uint8*)fBuffer + header->size - data;
758 	while (remainingBytes > 0) {
759 		if (remainingBytes < (int)sizeof(FieldHeader))
760 			return B_BAD_DATA;
761 		fieldHeader = (FieldHeader*)data;
762 		// check field header
763 		if (fieldHeader->type == B_ANY_TYPE)
764 			return B_BAD_DATA;
765 		if (fieldHeader->elementCount < 0)
766 			return B_BAD_DATA;
767 		if (fieldHeader->fieldSize < (int)sizeof(FieldHeader)
768 			|| fieldHeader->fieldSize > remainingBytes) {
769 			return B_BAD_DATA;
770 		}
771 		if (fieldHeader->headerSize < (int)sizeof(FieldHeader)
772 			|| fieldHeader->headerSize > fieldHeader->fieldSize) {
773 			return B_BAD_DATA;
774 		}
775 		int32 maxNameLen = data + fieldHeader->headerSize
776 			- (uint8*)fieldHeader->name;
777 		int32 nameLen = strnlen(fieldHeader->name, maxNameLen);
778 		if (nameLen == maxNameLen || nameLen == 0)
779 			return B_BAD_DATA;
780 		int32 fieldSize =  fieldHeader->headerSize;
781 		if (fieldHeader->HasFixedElementSize()) {
782 			// fixed element size
783 			int32 dataSize = fieldHeader->elementSize
784 				* fieldHeader->elementCount;
785 			fieldSize = (uint8*)fieldHeader->Data() + dataSize - data;
786 		} else {
787 			// non-fixed element size
788 			FieldValueHeader *valueHeader
789 				= (FieldValueHeader *)fieldHeader->Data();
790 			for (int32 i = 0; i < fieldHeader->elementCount; i++) {
791 				remainingBytes = (uint8*)fBuffer + header->size
792 					- (uint8*)valueHeader;
793 				if (remainingBytes < (int)sizeof(FieldValueHeader))
794 					return B_BAD_DATA;
795 				uint8 *value = (uint8*)valueHeader->Data();
796 				remainingBytes = (uint8*)fBuffer + header->size - (uint8*)value;
797 				if (remainingBytes < valueHeader->size)
798 					return B_BAD_DATA;
799 				fieldSize = value + valueHeader->size - data;
800 				valueHeader = valueHeader->NextFieldValueHeader();
801 			}
802 			if (fieldSize > fieldHeader->fieldSize)
803 				return B_BAD_DATA;
804 		}
805 		data = (uint8*)fieldHeader->NextFieldHeader();
806 		remainingBytes = (uint8*)fBuffer + header->size - data;
807 	}
808 	fLastFieldOffset = _BufferOffsetFor(fieldHeader);
809 	return B_OK;
810 }
811 
812 // _InitBuffer
813 void
814 KMessage::_InitBuffer(uint32 what)
815 {
816 	Header *header = _Header();
817 	header->magic = kMessageHeaderMagic;
818 	header->size = sizeof(Header);
819 	header->what = what;
820 	header->sender = -1;
821 	header->targetToken = -1;
822 	header->replyPort = -1;
823 	header->replyToken = -1;
824 	fLastFieldOffset = 0;
825 }
826 
827 // _CheckBuffer
828 void
829 KMessage::_CheckBuffer()
830 {
831 	int32 lastFieldOffset = fLastFieldOffset;
832 	if (_InitFromBuffer(false) != B_OK) {
833 		PANIC("internal data mangled");
834 	}
835 	if (fLastFieldOffset != lastFieldOffset) {
836 		PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()");
837 	}
838 }
839 
840 // _AllocateSpace
841 status_t
842 KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize,
843 	void **address, int32 *alignedSize)
844 {
845 	if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
846 		return B_NOT_ALLOWED;
847 
848 	int32 offset = ContentSize();
849 	if (alignAddress)
850 		offset = _Align(offset);
851 	int32 newSize = offset + size;
852 	if (alignSize)
853 		newSize = _Align(newSize);
854 	// reallocate if necessary
855 	if (fBuffer == &fHeader) {
856 		int32 newCapacity = _CapacityFor(newSize);
857 		void *newBuffer = malloc(newCapacity);
858 		if (!newBuffer)
859 			return B_NO_MEMORY;
860 		fBuffer = newBuffer;
861 		fBufferCapacity = newCapacity;
862 		fFlags |= KMESSAGE_OWNS_BUFFER;
863 		memcpy(fBuffer, &fHeader, sizeof(fHeader));
864 	} else {
865 		if (newSize > fBufferCapacity) {
866 			// if we don't own the buffer, we can't resize it
867 			if (!(fFlags & KMESSAGE_OWNS_BUFFER))
868 				return B_BUFFER_OVERFLOW;
869 			int32 newCapacity = _CapacityFor(newSize);
870 			void *newBuffer = realloc(fBuffer, newCapacity);
871 			if (!newBuffer)
872 				return B_NO_MEMORY;
873 			fBuffer = newBuffer;
874 			fBufferCapacity = newCapacity;
875 		}
876 	}
877 	_Header()->size = newSize;
878 	*address = (char*)fBuffer + offset;
879 	*alignedSize = newSize - offset;
880 	return B_OK;
881 }
882 
883 // _CapacityFor
884 int32
885 KMessage::_CapacityFor(int32 size)
886 {
887 	return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
888 		* kMessageReallocChunkSize;
889 }
890 
891 
892 // #pragma mark -
893 
894 // constructor
895 KMessageField::KMessageField()
896 	: fMessage(NULL),
897 	  fHeaderOffset(0)
898 {
899 }
900 
901 // Unset
902 void
903 KMessageField::Unset()
904 {
905 	fMessage = NULL;
906 	fHeaderOffset = 0;
907 }
908 
909 // Message
910 KMessage *
911 KMessageField::Message() const
912 {
913 	return fMessage;
914 }
915 
916 // Name
917 const char *
918 KMessageField::Name() const
919 {
920 	KMessage::FieldHeader* header = _Header();
921 	return (header ? header->name : NULL);
922 }
923 
924 // TypeCode
925 type_code
926 KMessageField::TypeCode() const
927 {
928 	KMessage::FieldHeader* header = _Header();
929 	return (header ? header->type : 0);
930 }
931 
932 // HasFixedElementSize
933 bool
934 KMessageField::HasFixedElementSize() const
935 {
936 	KMessage::FieldHeader* header = _Header();
937 	return (header ? header->HasFixedElementSize() : false);
938 }
939 
940 // ElementSize
941 int32
942 KMessageField::ElementSize() const
943 {
944 	KMessage::FieldHeader* header = _Header();
945 	return (header ? header->elementSize : -1);
946 }
947 
948 // AddElement
949 status_t
950 KMessageField::AddElement(const void *data, int32 size)
951 {
952 	KMessage::FieldHeader* header = _Header();
953 	if (!header || !data)
954 		return B_BAD_VALUE;
955 	if (size < 0) {
956 		size = ElementSize();
957 		if (size < 0)
958 			return B_BAD_VALUE;
959 	}
960 	return fMessage->_AddFieldData(this, data, size, 1);
961 }
962 
963 // AddElements
964 status_t
965 KMessageField::AddElements(const void *data, int32 count, int32 elementSize)
966 {
967 	KMessage::FieldHeader* header = _Header();
968 	if (!header || !data || count < 0)
969 		return B_BAD_VALUE;
970 	if (elementSize < 0) {
971 		elementSize = ElementSize();
972 		if (elementSize < 0)
973 			return B_BAD_VALUE;
974 	}
975 	return fMessage->_AddFieldData(this, data, elementSize, count);
976 }
977 
978 // ElementAt
979 const void *
980 KMessageField::ElementAt(int32 index, int32 *size) const
981 {
982 	KMessage::FieldHeader* header = _Header();
983 	return (header ? header->ElementAt(index, size) : NULL);
984 }
985 
986 // CountElements
987 int32
988 KMessageField::CountElements() const
989 {
990 	KMessage::FieldHeader* header = _Header();
991 	return (header ? header->elementCount : 0);
992 }
993 
994 // SetTo
995 void
996 KMessageField::SetTo(KMessage *message, int32 headerOffset)
997 {
998 	fMessage = message;
999 	fHeaderOffset = headerOffset;
1000 }
1001 
1002 // _GetHeader
1003 KMessage::FieldHeader*
1004 KMessageField::_Header() const
1005 {
1006 	return (fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL);
1007 }
1008 
1009