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