headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / messaging / KMessage.cpp
blob12127d97801123e338533f5d624fbeefdb85ec4d
1 /*
2 * Copyright 2005-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <util/KMessage.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include <ByteOrder.h>
13 #include <Debug.h>
14 #include <KernelExport.h>
15 #include <TypeConstants.h>
18 #if defined(_BOOT_MODE) || defined(_LOADER_MODE)
19 # include <util/kernel_cpp.h>
20 #else
21 # include <new>
22 #endif
25 // TODO: Add a field index using a hash map, so that lookup improves to O(1)
26 // (is now O(n)).
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
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
52 static const int32 kMessageReallocChunkSize = 64;
53 static const size_t kMessageBufferAlignment = 4;
55 const uint32 KMessage::kMessageHeaderMagic = 'kMsG';
58 // #pragma mark - Helper Functions
60 static inline int32
61 _Align(int32 offset)
63 return (offset + kMessageBufferAlignment - 1)
64 & ~(kMessageBufferAlignment - 1);
68 static inline void*
69 _Align(void* address, int32 offset = 0)
71 return (void*)(((addr_t)address + offset + kMessageBufferAlignment - 1)
72 & ~(kMessageBufferAlignment - 1));
76 // #pragma mark - FieldValueHeader
79 struct KMessage::FieldValueHeader {
80 int32 size;
82 void* Data()
84 return _Align(this, sizeof(FieldValueHeader));
87 FieldValueHeader* NextFieldValueHeader()
89 return (FieldValueHeader*)_Align(Data(), size);
94 // #pragma mark - FieldHeader
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];
105 void* Data()
107 return (uint8*)this + headerSize;
110 bool HasFixedElementSize()
112 return elementSize >= 0;
115 void* ElementAt(int32 index, int32* size)
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;
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();
132 FieldHeader* NextFieldHeader()
134 return (FieldHeader*)_Align(this, fieldSize);
139 // #pragma mark - KMessage
142 KMessage::KMessage()
144 fBuffer(NULL),
145 fBufferCapacity(0),
146 fFlags(0),
147 fLastFieldOffset(0)
149 Unset();
153 KMessage::KMessage(uint32 what)
155 fBuffer(NULL),
156 fBufferCapacity(0),
157 fFlags(0),
158 fLastFieldOffset(0)
160 Unset();
161 SetWhat(what);
165 KMessage::~KMessage()
167 Unset();
171 status_t
172 KMessage::SetTo(uint32 what, uint32 flags)
174 // There are no flags interesting in this case at the moment.
175 Unset();
176 SetWhat(what);
177 return B_OK;
181 status_t
182 KMessage::SetTo(void* buffer, int32 bufferSize, uint32 what, uint32 flags)
184 Unset();
186 if (!buffer)
187 return B_BAD_VALUE;
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;
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;
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;
207 fBuffer = buffer;
208 fBufferCapacity = bufferSize;
209 fFlags = flags;
211 status_t error = B_OK;
212 if (flags & KMESSAGE_INIT_FROM_BUFFER)
213 error = _InitFromBuffer(bufferSize < 0);
214 else
215 _InitBuffer(what);
217 if (error != B_OK)
218 Unset();
220 return error;
224 status_t
225 KMessage::SetTo(const void* buffer, int32 bufferSize, uint32 flags)
227 return SetTo(const_cast<void*>(buffer), bufferSize, 0,
228 KMESSAGE_INIT_FROM_BUFFER | KMESSAGE_READ_ONLY | flags);
232 void
233 KMessage::Unset()
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);
244 void
245 KMessage::SetWhat(uint32 what)
247 _Header()->what = what;
251 uint32
252 KMessage::What() const
254 return _Header()->what;
258 const void*
259 KMessage::Buffer() const
261 return fBuffer;
265 int32
266 KMessage::BufferCapacity() const
268 return fBufferCapacity;
272 int32
273 KMessage::ContentSize() const
275 return _Header()->size;
279 status_t
280 KMessage::AddField(const char* name, type_code type, int32 elementSize,
281 KMessageField* field)
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);
292 status_t
293 KMessage::FindField(const char* name, KMessageField* field) const
295 return FindField(name, B_ANY_TYPE, field);
299 status_t
300 KMessage::FindField(const char* name, type_code type,
301 KMessageField* field) const
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;
316 return B_NAME_NOT_FOUND;
320 status_t
321 KMessage::GetNextField(KMessageField* field) const
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;
336 if (fieldHeader == lastField)
337 return B_NAME_NOT_FOUND;
338 fieldHeader = fieldHeader->NextFieldHeader();
340 field->SetTo(const_cast<KMessage*>(this), _BufferOffsetFor(fieldHeader));
341 return B_OK;
345 bool
346 KMessage::IsEmpty() const
348 return _LastFieldHeader() == NULL;
352 status_t
353 KMessage::AddData(const char* name, type_code type, const void* data,
354 int32 numBytes, bool isFixedSize)
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;
370 return _AddFieldData(&field, data, numBytes, 1);
374 status_t
375 KMessage::AddArray(const char* name, type_code type, const void* data,
376 int32 elementSize, int32 elementCount)
378 if (!name || type == B_ANY_TYPE || !data || elementSize < 0
379 || elementCount < 0) {
380 return B_BAD_VALUE;
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;
393 return _AddFieldData(&field, data, elementSize, elementCount);
397 status_t
398 KMessage::SetData(const char* name, type_code type, const void* data,
399 int32 numBytes)
401 if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
402 return B_NOT_ALLOWED;
404 KMessageField field;
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;
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;
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;
426 // we've got an empty field -- add the element
427 return _AddFieldData(&field, data, numBytes, 1);
431 status_t
432 KMessage::FindData(const char* name, type_code type, const void** data,
433 int32* numBytes) const
435 return FindData(name, type, 0, data, numBytes);
439 status_t
440 KMessage::FindData(const char* name, type_code type, int32 index,
441 const void** data, int32* numBytes) const
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;
458 team_id
459 KMessage::Sender() const
461 return _Header()->sender;
465 int32
466 KMessage::TargetToken() const
468 return _Header()->targetToken;
472 port_id
473 KMessage::ReplyPort() const
475 return _Header()->replyPort;
479 int32
480 KMessage::ReplyToken() const
482 return _Header()->replyToken;
486 void
487 KMessage::SetDeliveryInfo(int32 targetToken, port_id replyPort,
488 int32 replyToken, team_id senderTeam)
490 Header* header = _Header();
491 header->sender = senderTeam;
492 header->targetToken = targetToken;
493 header->replyPort = replyPort;
494 header->replyToken = replyToken;
495 header->sender = senderTeam;
499 #ifndef KMESSAGE_CONTAINER_ONLY
502 status_t
503 KMessage::SendTo(port_id targetPort, int32 targetToken, port_id replyPort,
504 int32 replyToken, bigtime_t timeout, team_id senderTeam)
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;
513 senderTeam = info.team;
516 SetDeliveryInfo(targetToken, replyPort, replyToken, senderTeam);
518 // send the message
519 if (timeout < 0)
520 return write_port(targetPort, 'KMSG', fBuffer, ContentSize());
522 return write_port_etc(targetPort, 'KMSG', fBuffer, ContentSize(),
523 B_RELATIVE_TIMEOUT, timeout);
527 status_t
528 KMessage::SendTo(port_id targetPort, int32 targetToken, KMessage* reply,
529 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
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;
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);
560 struct PortDeleter {
561 PortDeleter(port_id port) : port(port) {}
562 ~PortDeleter()
564 if (port >= 0)
565 delete_port(port);
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;
582 status_t
583 KMessage::SendReply(KMessage* message, port_id replyPort, int32 replyToken,
584 bigtime_t timeout, team_id senderTeam)
586 if (!message)
587 return B_BAD_VALUE;
588 return message->SendTo(ReplyPort(), ReplyToken(), replyPort, replyToken,
589 timeout, senderTeam);
593 status_t
594 KMessage::SendReply(KMessage* message, KMessage* reply,
595 bigtime_t deliveryTimeout, bigtime_t replyTimeout, team_id senderTeam)
597 if (!message)
598 return B_BAD_VALUE;
599 return message->SendTo(ReplyPort(), ReplyToken(), reply, deliveryTimeout,
600 replyTimeout, senderTeam);
604 status_t
605 KMessage::ReceiveFrom(port_id fromPort, bigtime_t timeout,
606 port_message_info* messageInfo)
608 port_message_info _messageInfo;
609 if (messageInfo == NULL)
610 messageInfo = &_messageInfo;
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);
620 if (error != B_OK)
621 return error;
623 // allocate a buffer
624 uint8* buffer = (uint8*)MEMALIGN(kMessageBufferAlignment,
625 messageInfo->size);
626 if (!buffer)
627 return B_NO_MEMORY;
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;
637 if (messageInfo->size != (size_t)realSize) {
638 free(buffer);
639 return B_ERROR;
642 // init the message
643 return SetTo(buffer, messageInfo->size, 0,
644 KMESSAGE_OWNS_BUFFER | KMESSAGE_INIT_FROM_BUFFER);
648 #endif // !KMESSAGE_CONTAINER_ONLY
651 void
652 KMessage::Dump(void (*printFunc)(const char*, ...)) const
654 Header* header = _Header();
655 printFunc("KMessage: buffer: %p (size/capacity: %ld/%ld), flags: %#"
656 B_PRIx32 "\n", fBuffer, header->size, fBufferCapacity, fFlags);
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;
666 printFunc(" field: \"%s\"%*s (%.4s): ", field.Name(), nameSpacing, "",
667 (char*)&bigEndianType);
669 if (field.CountElements() != 1)
670 printFunc("\n");
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);
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;
706 if (isIntType)
707 printFunc("%lld (0x%llx)\n", intData, intData);
713 KMessage::Header*
714 KMessage::_Header() const
716 return (Header*)fBuffer;
720 int32
721 KMessage::_BufferOffsetFor(const void* data) const
723 if (!data)
724 return -1;
725 return (uint8*)data - (uint8*)fBuffer;
729 KMessage::FieldHeader*
730 KMessage::_FirstFieldHeader() const
732 return (FieldHeader*)_Align(fBuffer, sizeof(Header));
736 KMessage::FieldHeader*
737 KMessage::_LastFieldHeader() const
739 return _FieldHeaderForOffset(fLastFieldOffset);
743 KMessage::FieldHeader*
744 KMessage::_FieldHeaderForOffset(int32 offset) const
746 if (offset <= 0 || offset >= _Header()->size)
747 return NULL;
748 return (FieldHeader*)((uint8*)fBuffer + offset);
752 status_t
753 KMessage::_AddField(const char* name, type_code type, int32 elementSize,
754 KMessageField* field)
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;
775 status_t
776 KMessage::_AddFieldData(KMessageField* field, const void* data,
777 int32 elementSize, int32 elementCount)
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;
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;
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;
826 return B_OK;
830 status_t
831 KMessage::_InitFromBuffer(bool sizeFromBuffer)
833 if (fBuffer == NULL)
834 return B_BAD_DATA;
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;
844 void* buffer = MEMALIGN(kMessageBufferAlignment, fBufferCapacity);
845 if (buffer == NULL)
846 return B_NO_MEMORY;
848 memcpy(buffer, fBuffer, fBufferCapacity);
850 if ((fFlags & KMESSAGE_OWNS_BUFFER) != 0)
851 free(fBuffer);
853 fBuffer = buffer;
854 fFlags &= ~(uint32)(KMESSAGE_READ_ONLY | KMESSAGE_CLONE_BUFFER);
855 fFlags |= KMESSAGE_OWNS_BUFFER;
858 if (_Align(fBuffer) != fBuffer)
859 return B_BAD_DATA;
861 Header* header = _Header();
863 if (sizeFromBuffer)
864 fBufferCapacity = header->size;
866 if (fBufferCapacity < (int)sizeof(Header))
867 return B_BAD_DATA;
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;
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;
892 if (fieldHeader->headerSize < (int)sizeof(FieldHeader)
893 || fieldHeader->headerSize > fieldHeader->fieldSize) {
894 return B_BAD_DATA;
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();
923 if (fieldSize > fieldHeader->fieldSize)
924 return B_BAD_DATA;
926 data = (uint8*)fieldHeader->NextFieldHeader();
927 remainingBytes = (uint8*)fBuffer + header->size - data;
929 fLastFieldOffset = _BufferOffsetFor(fieldHeader);
930 return B_OK;
934 void
935 KMessage::_InitBuffer(uint32 what)
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;
949 void
950 KMessage::_CheckBuffer()
952 int32 lastFieldOffset = fLastFieldOffset;
953 if (_InitFromBuffer(false) != B_OK) {
954 PANIC("internal data mangled");
956 if (fLastFieldOffset != lastFieldOffset) {
957 PANIC("fLastFieldOffset changed during KMessage::_CheckBuffer()");
962 status_t
963 KMessage::_AllocateSpace(int32 size, bool alignAddress, bool alignSize,
964 void** address, int32* alignedSize)
966 if (fBuffer != &fHeader && (fFlags & KMESSAGE_READ_ONLY))
967 return B_NOT_ALLOWED;
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;
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;
1006 _Header()->size = newSize;
1007 *address = (char*)fBuffer + offset;
1008 *alignedSize = newSize - offset;
1009 return B_OK;
1013 int32
1014 KMessage::_CapacityFor(int32 size)
1016 return (size + kMessageReallocChunkSize - 1) / kMessageReallocChunkSize
1017 * kMessageReallocChunkSize;
1021 // #pragma mark - KMessageField
1024 KMessageField::KMessageField()
1026 fMessage(NULL),
1027 fHeaderOffset(0)
1032 void
1033 KMessageField::Unset()
1035 fMessage = NULL;
1036 fHeaderOffset = 0;
1040 KMessage*
1041 KMessageField::Message() const
1043 return fMessage;
1047 const char*
1048 KMessageField::Name() const
1050 KMessage::FieldHeader* header = _Header();
1051 return header ? header->name : NULL;
1055 type_code
1056 KMessageField::TypeCode() const
1058 KMessage::FieldHeader* header = _Header();
1059 return header ? header->type : 0;
1063 bool
1064 KMessageField::HasFixedElementSize() const
1066 KMessage::FieldHeader* header = _Header();
1067 return header ? header->HasFixedElementSize() : false;
1071 int32
1072 KMessageField::ElementSize() const
1074 KMessage::FieldHeader* header = _Header();
1075 return header ? header->elementSize : -1;
1079 status_t
1080 KMessageField::AddElement(const void* data, int32 size)
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;
1090 return fMessage->_AddFieldData(this, data, size, 1);
1094 status_t
1095 KMessageField::AddElements(const void* data, int32 count, int32 elementSize)
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;
1105 return fMessage->_AddFieldData(this, data, elementSize, count);
1109 const void*
1110 KMessageField::ElementAt(int32 index, int32* size) const
1112 KMessage::FieldHeader* header = _Header();
1113 return header ? header->ElementAt(index, size) : NULL;
1117 int32
1118 KMessageField::CountElements() const
1120 KMessage::FieldHeader* header = _Header();
1121 return header ? header->elementCount : 0;
1125 void
1126 KMessageField::SetTo(KMessage* message, int32 headerOffset)
1128 fMessage = message;
1129 fHeaderOffset = headerOffset;
1133 KMessage::FieldHeader*
1134 KMessageField::_Header() const
1136 return fMessage ? fMessage->_FieldHeaderForOffset(fHeaderOffset) : NULL;