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