xref: /haiku/src/system/kernel/messaging/KMessage.cpp (revision c0de5f6a5fbd231d8891b1f420617330ddba0735)
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 
52 static const int32 kMessageReallocChunkSize = 64;
53 static const size_t kMessageBufferAlignment = 4;
54 
55 const uint32 KMessage::kMessageHeaderMagic = 'kMsG';
56 
57 
58 // #pragma mark - Helper Functions
59 
60 static inline int32
_Align(int32 offset)61 _Align(int32 offset)
62 {
63 	return (offset + kMessageBufferAlignment - 1)
64 		& ~(kMessageBufferAlignment - 1);
65 }
66 
67 
68 static inline void*
_Align(void * address,int32 offset=0)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 
79 struct KMessage::FieldValueHeader {
80 	int32		size;
81 
DataKMessage::FieldValueHeader82 	void* Data()
83 	{
84 		return _Align(this, sizeof(FieldValueHeader));
85 	}
86 
NextFieldValueHeaderKMessage::FieldValueHeader87 	FieldValueHeader* NextFieldValueHeader()
88 	{
89 		return (FieldValueHeader*)_Align(Data(), size);
90 	}
91 };
92 
93 
94 // #pragma mark - FieldHeader
95 
96 
97 struct 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 
DataKMessage::FieldHeader105 	void* Data()
106 	{
107 		return (uint8*)this + headerSize;
108 	}
109 
HasFixedElementSizeKMessage::FieldHeader110 	bool HasFixedElementSize()
111 	{
112 		return elementSize >= 0;
113 	}
114 
ElementAtKMessage::FieldHeader115 	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 
NextFieldHeaderKMessage::FieldHeader132 	FieldHeader* NextFieldHeader()
133 	{
134 		return (FieldHeader*)_Align(this, fieldSize);
135 	}
136 };
137 
138 
139 // #pragma mark - KMessage
140 
141 
KMessage()142 KMessage::KMessage()
143 	:
144 	fBuffer(NULL),
145 	fBufferCapacity(0),
146 	fFlags(0),
147 	fLastFieldOffset(0)
148 {
149 	Unset();
150 }
151 
152 
KMessage(uint32 what)153 KMessage::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 
~KMessage()165 KMessage::~KMessage()
166 {
167 	Unset();
168 }
169 
170 
171 status_t
SetTo(uint32 what,uint32 flags)172 KMessage::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 
181 status_t
SetTo(void * buffer,int32 bufferSize,uint32 what,uint32 flags)182 KMessage::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 
224 status_t
SetTo(const void * buffer,int32 bufferSize,uint32 flags)225 KMessage::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 
232 void
Unset()233 KMessage::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 
244 void
SetWhat(uint32 what)245 KMessage::SetWhat(uint32 what)
246 {
247 	_Header()->what = what;
248 }
249 
250 
251 uint32
What() const252 KMessage::What() const
253 {
254 	return _Header()->what;
255 }
256 
257 
258 const void*
Buffer() const259 KMessage::Buffer() const
260 {
261 	return fBuffer;
262 }
263 
264 
265 int32
BufferCapacity() const266 KMessage::BufferCapacity() const
267 {
268 	return fBufferCapacity;
269 }
270 
271 
272 int32
ContentSize() const273 KMessage::ContentSize() const
274 {
275 	return _Header()->size;
276 }
277 
278 
279 status_t
AddField(const char * name,type_code type,int32 elementSize,KMessageField * field)280 KMessage::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 
292 status_t
FindField(const char * name,KMessageField * field) const293 KMessage::FindField(const char* name, KMessageField* field) const
294 {
295 	return FindField(name, B_ANY_TYPE, field);
296 }
297 
298 
299 status_t
FindField(const char * name,type_code type,KMessageField * field) const300 KMessage::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 
320 status_t
GetNextField(KMessageField * field) const321 KMessage::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 
345 bool
IsEmpty() const346 KMessage::IsEmpty() const
347 {
348 	return _LastFieldHeader() == NULL;
349 }
350 
351 
352 status_t
AddData(const char * name,type_code type,const void * data,int32 numBytes,bool isFixedSize)353 KMessage::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 
374 status_t
AddArray(const char * name,type_code type,const void * data,int32 elementSize,int32 elementCount)375 KMessage::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 
397 status_t
SetData(const char * name,type_code type,const void * data,int32 numBytes)398 KMessage::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 
431 status_t
FindData(const char * name,type_code type,const void ** data,int32 * numBytes) const432 KMessage::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 
439 status_t
FindData(const char * name,type_code type,int32 index,const void ** data,int32 * numBytes) const440 KMessage::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 
458 team_id
Sender() const459 KMessage::Sender() const
460 {
461 	return _Header()->sender;
462 }
463 
464 
465 int32
TargetToken() const466 KMessage::TargetToken() const
467 {
468 	return _Header()->targetToken;
469 }
470 
471 
472 port_id
ReplyPort() const473 KMessage::ReplyPort() const
474 {
475 	return _Header()->replyPort;
476 }
477 
478 
479 int32
ReplyToken() const480 KMessage::ReplyToken() const
481 {
482 	return _Header()->replyToken;
483 }
484 
485 
486 void
SetDeliveryInfo(int32 targetToken,port_id replyPort,int32 replyToken,team_id senderTeam)487 KMessage::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 
502 status_t
SendTo(port_id targetPort,int32 targetToken,port_id replyPort,int32 replyToken,bigtime_t timeout,team_id senderTeam)503 KMessage::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 
527 status_t
SendTo(port_id targetPort,int32 targetToken,KMessage * reply,bigtime_t deliveryTimeout,bigtime_t replyTimeout,team_id senderTeam)528 KMessage::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 
582 status_t
SendReply(KMessage * message,port_id replyPort,int32 replyToken,bigtime_t timeout,team_id senderTeam)583 KMessage::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 
593 status_t
SendReply(KMessage * message,KMessage * reply,bigtime_t deliveryTimeout,bigtime_t replyTimeout,team_id senderTeam)594 KMessage::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 
604 status_t
ReceiveFrom(port_id fromPort,bigtime_t timeout,port_message_info * messageInfo)605 KMessage::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 
651 void
Dump(void (* printFunc)(const char *,...)) const652 KMessage::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 
713 KMessage::Header*
_Header() const714 KMessage::_Header() const
715 {
716 	return (Header*)fBuffer;
717 }
718 
719 
720 int32
_BufferOffsetFor(const void * data) const721 KMessage::_BufferOffsetFor(const void* data) const
722 {
723 	if (!data)
724 		return -1;
725 	return (uint8*)data - (uint8*)fBuffer;
726 }
727 
728 
729 KMessage::FieldHeader*
_FirstFieldHeader() const730 KMessage::_FirstFieldHeader() const
731 {
732 	return (FieldHeader*)_Align(fBuffer, sizeof(Header));
733 }
734 
735 
736 KMessage::FieldHeader*
_LastFieldHeader() const737 KMessage::_LastFieldHeader() const
738 {
739 	return _FieldHeaderForOffset(fLastFieldOffset);
740 }
741 
742 
743 KMessage::FieldHeader*
_FieldHeaderForOffset(int32 offset) const744 KMessage::_FieldHeaderForOffset(int32 offset) const
745 {
746 	if (offset <= 0 || offset >= _Header()->size)
747 		return NULL;
748 	return (FieldHeader*)((uint8*)fBuffer + offset);
749 }
750 
751 
752 status_t
_AddField(const char * name,type_code type,int32 elementSize,KMessageField * field)753 KMessage::_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 
775 status_t
_AddFieldData(KMessageField * field,const void * data,int32 elementSize,int32 elementCount)776 KMessage::_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 
830 status_t
_InitFromBuffer(bool sizeFromBuffer)831 KMessage::_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 
934 void
_InitBuffer(uint32 what)935 KMessage::_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 
949 void
_CheckBuffer()950 KMessage::_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 
962 status_t
_AllocateSpace(int32 size,bool alignAddress,bool alignSize,void ** address,int32 * alignedSize)963 KMessage::_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 
1013 int32
_CapacityFor(int32 size)1014 KMessage::_CapacityFor(int32 size)
1015 {
1016 	return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
1017 		* kMessageReallocChunkSize;
1018 }
1019 
1020 
1021 // #pragma mark - KMessageField
1022 
1023 
KMessageField()1024 KMessageField::KMessageField()
1025 	:
1026 	fMessage(NULL),
1027 	fHeaderOffset(0)
1028 {
1029 }
1030 
1031 
1032 void
Unset()1033 KMessageField::Unset()
1034 {
1035 	fMessage = NULL;
1036 	fHeaderOffset = 0;
1037 }
1038 
1039 
1040 KMessage*
Message() const1041 KMessageField::Message() const
1042 {
1043 	return fMessage;
1044 }
1045 
1046 
1047 const char*
Name() const1048 KMessageField::Name() const
1049 {
1050 	KMessage::FieldHeader* header = _Header();
1051 	return header ? header->name : NULL;
1052 }
1053 
1054 
1055 type_code
TypeCode() const1056 KMessageField::TypeCode() const
1057 {
1058 	KMessage::FieldHeader* header = _Header();
1059 	return header ? header->type : 0;
1060 }
1061 
1062 
1063 bool
HasFixedElementSize() const1064 KMessageField::HasFixedElementSize() const
1065 {
1066 	KMessage::FieldHeader* header = _Header();
1067 	return header ? header->HasFixedElementSize() : false;
1068 }
1069 
1070 
1071 int32
ElementSize() const1072 KMessageField::ElementSize() const
1073 {
1074 	KMessage::FieldHeader* header = _Header();
1075 	return header ? header->elementSize : -1;
1076 }
1077 
1078 
1079 status_t
AddElement(const void * data,int32 size)1080 KMessageField::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 
1094 status_t
AddElements(const void * data,int32 count,int32 elementSize)1095 KMessageField::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 
1109 const void*
ElementAt(int32 index,int32 * size) const1110 KMessageField::ElementAt(int32 index, int32* size) const
1111 {
1112 	KMessage::FieldHeader* header = _Header();
1113 	return header ? header->ElementAt(index, size) : NULL;
1114 }
1115 
1116 
1117 int32
CountElements() const1118 KMessageField::CountElements() const
1119 {
1120 	KMessage::FieldHeader* header = _Header();
1121 	return header ? header->elementCount : 0;
1122 }
1123 
1124 
1125 void
SetTo(KMessage * message,int32 headerOffset)1126 KMessageField::SetTo(KMessage* message, int32 headerOffset)
1127 {
1128 	fMessage = message;
1129 	fHeaderOffset = headerOffset;
1130 }
1131 
1132 
1133 KMessage::FieldHeader*
_Header() const1134 KMessageField::_Header() const
1135 {
1136 	return fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL;
1137 }
1138