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