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