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