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